1. 程式人生 > >java基礎知識-面試(二)

java基礎知識-面試(二)

  • Connections和Connection有何區別?
    java.util.Collection是一個集合介面,它提供了對集合物件進行基本操作的通用介面方法,Connection介面在java類庫中有很多具體的實現,Connection的意義是為各種具體的集合提供了最大化的同一操作方式

List 、Set、Queue介面都繼承Connection

這裡寫圖片描述

AbstractConnection —實現了connection介面,並對簡單一些方法做了實現比如isEmpty();

java.util.connections是一個包裝類,它包含各種集合操作的靜態方法(對集合的搜尋、排序,執行緒安全化),大多數方法都是用來處理線性表,此類不能例項化,更像一個工具 ,服務於java的Connection

這裡寫圖片描述

connection是一個頂級介面,像List、Set、Queue等屬於
connections是一個工具類,提供很多靜態方法來操作集合

List、Set、Map的區別?Map是否繼承Conllection介面

List :可以允許重複的物件
可以插入多個null元素
是有序的,保持了每個元素的插入順序,輸出的順序就是插入的順序
常用的List有ArrayList 、LinkedList,ArrayList最為流行,它提供了使用索引的隨意訪問,而LinkedList則對於經常需要從List新增或刪除元素的場合更為合適

Set:不允許重複物件,
無序容器,你無法保證每個元素的儲存順序,TreeSet通過Comparator維護了一個排序順序
只允許一個null元素
Set最流行的幾個介面是HashSet、LinkedSet以及TreeSet

List、Set、Queue繼承Connection介面,Map不是

Map:
Map不是connection的子介面或者實現類,Map是一個介面
Map的每一個Entry都是一個鍵值對,Map可能會有持有相同值物件但鍵物件不同(鍵物件必須是唯一的,否則會覆蓋)
TreeMap也通過Comparator或者Comparable維護了一個排序順序

Map裡邊可以擁有隨意多個null值,但是隻能有一個null鍵

Map最常用的幾個實現類:HashMap、LinkedMap、HashTable、TreeMap (HashMap和TreeMap最為常見)

ArrayList和LinkedList的區別?
1.ArrayList是基於動態陣列實現的資料結構,動態擴容(預設初始大小是10),而LinkedList是基於連結串列的資料結構(Node內部類,next、pre、elemnet)
2.對於隨機訪問get和set,ArrayList要優於LinkedList,因為LinkedList要移動指標,
3.對於新增和刪除操作add和remove,LinkedList要比ArrayList要快的多(資料多的情況下很明顯)

ArrayList中的元素如何刪除?
強烈使用Iterator,保證正確

這裡寫圖片描述

這裡寫圖片描述
Iterator迭代器實現
從後往前遍歷

Iterator和LitsIterator區別?
LitsIterator 繼承Iterator介面
Iterator 有hasNext()方法,是否有下一個元素
next:指向後面的元素
remove:刪除集合中Iterator指向位置後面的元素
LitsIterator方法:(更多方法)
add(E e):將指定元素插入當前位置之前
hasPrevious:前面是否還有元素
nextIndex():返回所需位置的索引

相同點:都是迭代器,當需要對集合元素進行遍歷不需要干涉其遍歷過程時,這兩種迭代器都可以使用

不同點:使用範圍不同,Iterator可以應用於所有的集合,Set、List、Map和這些集合的子型別,而ListIterator只能用於List及其子型別

2.ListIterator有add方法,可以向list中新增物件,而Iterator不能

3.ListIterator和Iterator都有hasNext()和next()方法,可以實現順序向後遍歷,但是ListIterator有hasPrevious和previous方法,可以實現逆向(從後向前)遍歷,Iterator不可以

4.ListIterator可以實現定位當前索引位置,NextIndex可以,而Iterator不可以

5.都可以實現刪除操作,但是ListIterator可以實現物件的修改,set方法可以實現,但是Iterator僅能遍歷,不能修改

Comparable和Conparator的區別?
兩個都是介面
相同點:都是用來實現集合重元素的比較
不同點:Comparable接口裡面的方法是public int compareTo(T o)在java.lang包下
Comparator接口裡面的方法是int compare(T o1,T o2)在java.util包下

Comparable是在集合內部定義的方法實現的排序,Comparator是在集合外部實現的排序

所以要想實現排序,就需要在集合外定義的Comparator介面的方法活在集合內實現Comparable介面的方法。Comparable是一個物件本身就已經支援字比較所需要實現的介面(如String、Integer、Float、Double等),自己就可以完成比較大小操作,已經實現了Comparable介面,自定義的類要在加入容器時,實現Comparable介面,在用Conlections類的sort方法進行排序,如果不指定Comparator,那麼就以自然順序排序,這裡的自然順序就是實現Comparable介面設定的排序模式

而Comparator是一個專用的比較器,在集合外部實現的排序,當這個物件不支援自比較或者自比較函式不能滿足你的要求時,你可以寫一個比較器來完成兩個物件之間大小的比較
用Comparator是策略模式,就是不改變物件自身,而用一個策略物件來改變它的行為,比如,你想對整數採用絕對值大小來怕許,Integer是不符合要求的,你不需要去修改Integer類,(實際上也不能這麼做),只要使用了一個實現了Conparator的介面的物件來控制它的排序就好了

簡單來說Comparable是自己完成比較,Comparator是外部程式實現比較(集合外部實現的排序)

工作中如何使用?
1.一個類既可以實現Comparable介面也可以實現Comparator介面
如果希望一個類的比較方式有很多種,而且比較方式具有外部擴充套件性,那麼可以實現Comparator介面,如果一個類預設的實現了Comparable介面,而你又希望再定義一個比較規則,那麼你不可能去修改原類,因為這樣會破壞封閉開放原則,最好的方法就是寫一個實現了Comparator介面的類,總的來說,Comparator介面比Comparable更靈活
2.如果一個集合類中存放著一些物件,如果希望對這個集合進行排序,可以使用Collections類裡面的sort方法,或者Arrays.sort方法
sort方法有兩種過載方式:
sort(Collection c):這種方法是根據類T裡面預設的規則來進行排序的,即類裡面有compareTo方法
sort(Collections c ,Comparator com):這種方法是根據類外面穿進來的Comparator實現類排序的,可以自定義排序規則

有的類已經實現了Comparable方法(String/Integer/double、float等List)可直接呼叫sort方法,預設升序排序

成績屬性如何排序
實現Comparable介面,實現compareTo方法,
Comparator介面,實現compare方法

java中的ArrayList和HashMap預設容量?

在java7中,ArrayList預設大小是10個元素
HashMap的預設容量是16(必須是2的冪),負載因子0.75
動態擴容,達到負載因子,就會進行擴容

jdk1,8中
ArrayList包含了兩個重要的物件
elementData和size
elementData是Object陣列,他儲存了新增到ArrayList中的元素,實際上elementData是一個動態陣列,我們可以通過建構函式ArrayList(int initialCapacity)來執行它的初始容量為InitialCapacity,如果通過不含引數的建構函式ArrayList來建立ArrayList,則在第一次新增元素的時候初始化elementData的預設容量是10,elementData陣列大小會根據ArrayList陣列的增長而動態增長,具體的增長方式,請參考原始碼分析中的ensureCapacity()函式
size則是動態陣列的實際大小
jdk1.7中是呼叫預設建構函式this(10),初始化大小為10

HashMap和ArrayList一樣,也是第一次新增元素的時候出初始化預設容量

hashCode()和equals方法有什麼重要性?
hashCode()和equals()方法的作用其實一樣,在java裡面都是用來對比兩個物件是否相等一致

在java中任何一個物件都具備equals和hashCode方法,因為他們是在Object類中定義的

equals方法是用來判斷兩個物件是否相同,如相同則返回true,否則返回false
hashCode方法返回一個int數,在Object中預設的實現是“將物件的記憶體地址轉換成一個整數返回”
native方法

equals方法的最用:
1.預設情況(沒有覆蓋equals)都是呼叫了Object類的equals方法,而Object的equals方法主要用於判斷兩個物件的記憶體地址是否是同一個地址(是不是同一個物件)
2.要是類中覆蓋了equals方法,那麼就要根據具體的程式碼來確定equals方法的作用了,覆蓋後一般都是通過物件的內容是否相等來判斷物件是否相等

hashCode方法的作用:
hashCode方法是為了提高在雜湊結構儲存中查詢的效率(定位在hash表中的位置),線上性表中沒有作用,hashCode方法只在集合中用到,以Hash開頭的集合類

雜湊碼
雜湊碼的產生依據,雜湊碼並不是完全唯一的,它是一種演算法,讓同一類的物件按照自己不同的特徵儘量有不同的雜湊碼,但不表示不同的物件hash碼完全不同,也有相同情況,看程式設計師如何看待雜湊演算法
在java中,雜湊碼代表物件的特徵:
String str1 = “aa”; str1.hashCode =3014
String str2 = “bb”; str1.hashCode =3016
String str3 = “aa”; str1.hashCode =3014
根據hashcode由此可得出:str1!=str2 ; str1 == str3
幾個常見的雜湊碼的演算法:
1.Object類的hashCode,返回物件的記憶體地址經過處理後的機構,由於每個物件的記憶體地址都不一樣,所以HashCode也不一樣
2.String類(重寫了hashCode)的HashCode,根據String中包含的字串的內容,根據一種特殊演算法返回雜湊碼,只要字串所在的堆空間相同,返回的雜湊碼也相同
3.Integer類,返回的HashCode 就是Integer物件裡所包含的那個整數的值,例如Integer i1 = new Integer(100),i1的hashcode值就是100
由此可見,2個大小一樣的Integer物件,返回的雜湊碼也一樣

那麼equals既然已經實現對比的功能了,為什麼還要hashCode呢?
因為重寫的equals裡一般比較的 比較全面、比較複雜,這樣效率就比較低,而利用hashCode方法進行對比則只要生成一個hash值進行比較就可以了,效率很高

那麼hashCode既然這麼高效,為什麼還要equals?
因為hashCode(並不是完全可靠,有的時候不同的物件生成的hashcode也會一樣(生成的hash值公式可能存在問題)所以hashCode()只能說是大部分時間可靠,並不是絕對可靠,所以我們在使用的時候,按照下面的規範:

1.若是重寫了equals方法,則有必要重寫hashCode方法
得出結論:
equals相等的兩個物件他們的hashCode一定相等,也就是equals對比是絕對可靠的
hashCode相等的兩個物件他們的equals不一定相等,也就是hashCode不是絕對可靠的

詳細的說明:
若是重寫了equals方法,則有必要重寫hashCode方法
若兩個物件的equals方法返回true,則hashCode有必要返回相同的int數
若兩個物件的equals方法返回false,則hashCode有不一定返回相同的int數
若兩個物件hashcode返回相同的int數,則兩個物件的equals方法不一定返回true
若兩個物件hashcode返回不同的int數,則兩個物件的equals方法一定返回false
同一物件在執行期間若已儲存在集合中,則不能修改影響hashCode的相關資訊,否則會導致記憶體洩漏等問題

最佳實踐:
所有對於大量並且快速的對比的話都要用equals去做顯然效率太低,所以解決方法是每當需要對比的時候,首先用hashCode去對比,如果hashCode不一樣,則表示這兩個物件肯定不相同(沒必要再去用equals對比),如果hashCode相等,此時再對比它們的equals,如果equals相等,則表示這兩個物件是真的相同了,這樣既能大大提高了效率也保證了對比的絕對正確性

這種大量的並且快速的物件對比一般使用在Hash容器中,比如HashSet、HashMap、HashTable等等,比如hashSet要求元素不能重複,則它的內部必須要對新增進去的元素物件進行對比,而它的比對規則就是象上面說的那樣,先hashCode,如果hashCode相同,在比對equals ,如果hashCode都不同,則肯定不同,這樣對比的效率就會很高

必須是在hash容器中先hashCode,如果hashCode相同才會比較equals,如果hashCode不同,則認為不同物件,不會比較equals

如果不在容器中,就是看對應的equals方法是否相等,於HashCode沒有關係、

修改學生的年齡,hashcode的值會改變
當我們將某個物件儲存到set中,如果該物件的屬性參與了hashcode計算,那麼以後就不能修改該物件參與hashcode計算的那些屬性了,否則會引起意想不到問題

這裡寫圖片描述

會刪除失敗,因為刪除的時候也要根據hash碼判斷,此時找不到hashcode的值,所以無法刪除。

HashSet和TreeSet有什麼區別?
HashSet:
不能保證元素的排序順序,順序有可能發生變化,不允許一樣重複的物件—無序的
集合元素可以是null,但是隻能放一個null
HashSet底層是採用HashMap實現的
HashSet底層是一個雜湊表

只利用hashMap中的key鍵來完成 ,value不用,將值儲存到key中即可

TreeSet
TreeSet中的資料是排好序的,不允許放入null值,與插入順序無關,比如字串,按首字母大小寫排序自然排序
TreeSet是通過TreeMap來實現的,只不過set用的只是map的key值
TreeSet底層實現的是採用二叉樹(紅黑樹)的資料結構

TreeSet物件裡面放字串:
這裡寫圖片描述

TreeSet物件裡面放入物件
這裡寫圖片描述

Comparable–實現介面,實現compareTo方法
Comparator–實現介面,實現compare方法、定義在類外部,比較專用的比較器
TreeSet tsc = new TreeSet(new MyCompare());

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

HashSet:
當向HashSet集合中存入一個元素時,HashSet會呼叫物件的hashCode方法來得到該物件的hashCode值,然後根據hashcode值來決定物件在HashSet中的儲存位置,如果相等,那就不能插入,如果不等,才回去呼叫equals方法,如果equals方法為true,說明已經存在,就不能插入,如果為false,則可以插入

簡單來說,HashSet集合判斷兩個元素是否相等的標準是兩個物件通過equals方法比較相等,並且兩個物件的hashcode方法返回值相等

簡單來說,如果要把一個物件放入HashSet中,重寫該物件對應類的equals方法,也因該重寫其hashCode方法,其規則是如果兩個物件equals比較相同返回true時,其HashCode也應該相同,物件中用作比較equals的屬性,都應該參與計算hashCode的值

TreeSet:
TreeSet是怎麼實現有序的,它是按照什麼規則排序的

TreeSet的底層是採用紅黑樹的資料結構,採用這種結構可以從Set中獲取有序的序列,但是前提條件是:元素必須實現Comparable介面,該介面中只有一個方法comparaTo方法,當往Set集合中插入一個新的元素的時候,首先會遍歷Set中已經存在的元素,並呼叫compareTo方法,根據返回的結果決定插入的位置,這樣也就保證了元素的順序

TreeSet是SortedSet介面唯一的實現類,TreeSet可以確保集合元素處於排序狀態,TreeSet支援兩種排序方式:自然排序和定製排序,其中自然排序為預設的排序方式
字串預設 —–字母大小寫排序

用Student類做Map的key值需要重寫哪些方法?

使用HashMap等,如果是自定義的類,就必須重寫equals和hashcode

HashMap的工作原理介紹下,是執行緒安全的嗎?
1.底層資料結構
HashMap底層用的是雜湊表,雜湊表是由陣列和連結串列組成

雜湊表的優勢:
陣列是儲存空間連續的,佔用記憶體嚴重,故空間複雜度很大,但陣列的二分查詢時間複雜度小,為o(1),陣列的特點:定址容易,插入和刪除資料難
連結串列:連結串列儲存空間離散,佔用記憶體較為寬鬆,故空間複雜度很小,但時間複雜度很大,達到O(n),連結串列的特點:定址困難,但是插入和刪除元素較為簡單

雜湊表:
那我們能不能綜合兩者的特性,做出一種定址容易,插入刪除也方便的資料解耦,答案是肯定的,這就是我們提到的雜湊表
HashTable既滿足了資料的查詢方便,同時也不用佔用多型的內容空間,使用也十分方便
雜湊表有多種不同的實現方法:最常用的就是拉鍊法可以理解為連結串列的陣列,陣列和連結串列的結合體

陣列中每一個元素產生連結串列–發生碰撞的時候,就會在hashcode後面儲存連結串列

另外一個說法:大家遇到的時候要知道:HashMap採用位桶(bucket)+連結串列實現
對於HashMap以及子類而言,它們呢採用Hash演算法來決定集合中元素的儲存位置,當系統開始初始化HashMap時,系統會自動建立長度為capacity長度的Entry陣列,這個數組裡可以儲存元素的位置被稱為桶(Bucket),每一個bucket都有其指定索引,系統可以根據索引快速訪問該bucket裡儲存的元素。
無論何時,HashMap的每個桶只能儲存一個元素,也就是一個Entry,由於Entry物件可以包含一個引用變數,就是 Entry構造器的最後一個引數,用於指向下一個Entry陣列,因此可能出現的情況是:HashMap的bucket中只有一個Entry,但這個Entry指向另一個Entry,這就形成了一個Entry鏈

如何實現快速的存取?
HashMap的get實現
當HashMap的每個bucket裡儲存的Entry只是單個Entry,也就是沒有通過指標產生Entry鏈時,此時的HashMap具有最好的效能,當程式通過key值取出對應的value值時,系統 只要先計算出該key的hashcode的返回碼,在根據hashCode返回值找出該key在table陣列中的索引,然後取出該索引處的Entry,最後返回該key值對應的value值即可。

這裡寫圖片描述

HashMap的put操作:
對key的hashCode()做hash,然後在計算index,
如果沒有碰撞則直接放到bucket,
如果碰撞了,以連結串列的形式存在buckets之後,
如果節點已經存在就替換old value(保證key的唯一性)
不存在時如果buckets滿了,(超過load factor * current capacity)就要resize(擴容)
說明:當key值出現hash衝突的時候,連結串列中的第一個元素都是最後面新增進來的元素,之前的責備next變數引用著

這裡寫圖片描述

這裡寫圖片描述

Entry是HashMap中的靜態內部類
初始化容量16 負載因子0.75
擴容演算法

原始碼核心:
jdk1.7和jdk.18是不同的
HashMap裡面實現一個靜態內部類,其重要的屬性有key/value/next,從屬性key、value我們就能夠很面先看出來Entry就是HashMap裡面鍵值對實現的一個基礎bean,HashMap的基礎就是一個線性陣列,這個陣列的就是Entry,Map裡面儲存的內容都儲存在Entry裡面,Entry是一個單向連結串列

HashMap不是執行緒安全的(方法中很多有synchronize策略關鍵字),ConcurrentHashMap是執行緒安全的,核心Set內部類

集合框架中的泛型介紹下?
java泛型(gengerics)是jdk1.5中引入的一個新特性,泛型提供了編譯時型別安全檢測機制,該機制允許程式在編譯時檢測到非法的型別
泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數

思考?假定我們有這樣一個需求,寫一個排序方法,能夠針對整數型陣列、字串陣列什麼其他任何型別的陣列進行排序,該如何實現?
當然是可以使用java泛型

泛型方法
可以寫一個泛型方法,該方法呼叫時可以接受不同型別的引數,根據傳遞給泛型方法的引數型別,編譯器適當的處理每一個方法呼叫

這裡寫圖片描述

2.有界的型別引數:
可能有時候,你會想限制哪些被允許傳遞到一個型別引數的型別種類範圍,例如:一個運算元字的方法可能只希望接受Number或者Number子類的例項,這就是有界引數地目的

要宣告一個有界的引數型別,首先列出型別引數的名稱,後跟上引數的名稱,後跟extends關鍵字,最後緊跟它的上限

這裡寫圖片描述

3.泛型類

泛型類的宣告和非泛型類的宣告類似,除了在類名後面加了型別引數宣告部分
和泛型方法一樣,泛型類的引數宣告部分也包含一個或者多個型別引數,引數用逗號隔開,一個泛型引數也可被稱為一個型別變數,用於指定一個泛型型別的名稱識別符號,因為他們接受一個或多個引數,這些類被稱為引數化的類或引數化的型別

  • 程式碼塊高亮
  • 圖片連結和圖片上傳
  • LaTex數學公式
  • UML序列圖和流程圖
  • 離線寫部落格
  • 匯入匯出Markdown檔案
  • 豐富的快捷鍵

快捷鍵

  • 加粗 Ctrl + B
  • 斜體 Ctrl + I
  • 引用 Ctrl + Q
  • 插入連結 Ctrl + L
  • 插入程式碼 Ctrl + K
  • 插入圖片 Ctrl + G
  • 提升標題 Ctrl + H
  • 有序列表 Ctrl + O
  • 無序列表 Ctrl + U
  • 橫線 Ctrl + R
  • 撤銷 Ctrl + Z
  • 重做 Ctrl + Y

Markdown及擴充套件

Markdown 是一種輕量級標記語言,它允許人們使用易讀易寫的純文字格式編寫文件,然後轉換成格式豐富的HTML頁面。 —— [ 維基百科 ]

使用簡單的符號標識不同的標題,將某些文字標記為粗體或者斜體,建立一個連結等,詳細語法參考幫助?。

本編輯器支援 Markdown Extra ,  擴充套件了很多好用的功能。具體請參考Github.

表格

Markdown Extra 表格語法:

專案 價格
Computer $1600
Phone $12
Pipe $1

可以使用冒號來定義對齊方式:

專案 價格 數量
Computer 1600 元 5
Phone 12 元 12
Pipe 1 元 234

定義列表

Markdown Extra 定義列表語法:
專案1
專案2
定義 A
定義 B
專案3
定義 C

定義 D

定義D內容

程式碼塊

程式碼塊語法遵循標準markdown程式碼,例如:

@requires_authorization
def somefunc(param1='', param2=0):
    '''A docstring'''
    if param1 > param2: # interesting
        print 'Greater'
    return (param2 - param1 + 1) or None
class SomeClass:
    pass
>>> message = '''interpreter
... prompt'''

腳註

生成一個腳註1.

目錄

[TOC]來生成目錄:

數學公式

  • 行內公式,數學公式為:Γ(n)=(n1)!nN
  • 塊級公式:
x=b±b24ac2a

更多LaTex語法請參考 這兒.

UML 圖:

可以渲染序列圖:

Created with Raphaël 2.1.2張三張三李四李四嘿,小四兒, 寫部落格了沒?李四愣了一下,說:忙得吐血,哪有時間寫。

或者流程圖:

Created with Raphaël 2.1.2開始我的操作確認?結束yesno
  • 關於 序列圖 語法,參考 這兒,
  • 關於 流程圖 語法,參考 這兒.

離線寫部落格

即使使用者在沒有網路的情況下,也可以通過本編輯器離線寫部落格(直接在曾經使用過的瀏覽器中輸入write.blog.csdn.net/mdeditor即可。Markdown編輯器使用瀏覽器離線儲存將內容儲存在本地。

使用者寫部落格的過程中,內容實時儲存在瀏覽器快取中,在使用者關閉瀏覽器或者其它異常情況下,內容不會丟失。使用者再次開啟瀏覽器時,會顯示上次使用者正在編輯的沒有發表的內容。

部落格發表後,本地快取將被刪除。 

使用者可以選擇 把正在寫的部落格儲存到伺服器草稿箱,即使換瀏覽器或者清除快取,內容也不會丟失。

注意:雖然瀏覽器儲存大部分時候都比較可靠,但為了您的資料安全,在聯網後,請務必及時發表或者儲存到伺服器草稿箱

瀏覽器相容

  1. 目前,本編輯器對Chrome瀏覽器支援最為完整。建議大家使用較新版本的Chrome。
  2. IE9以下不支援
  3. IE9,10,11存在以下問題
    1. 不支援離線功能
    2. IE9不支援檔案匯入匯出
    3. IE10不支援拖拽檔案匯入
  1. 這裡是 腳註內容.