Java集合的深度理解

010HelloWord發表於2018-04-21

宣告一下總結這些之前還沒有學泛型.所以所敲程式碼警告較多。

1.

一級介面:Collection,

二級介面:List Set

三級實現類:ArrayList類,LinkedList類, HashSet類, LinkedHashSet類, TreeSet類

其中,

注意事項:一級介面指向三級實現子類(ArrayList類, LinkedList類, HashSet類,LinkedHashSet類, TreeSet類 )的時候,例如 Collection con =new ArrayList();其中ArrayList()可用其他三級實現子類代替

con.add("aa");

con.add(newString("AA"));

con.contains(new String("AA"));//返回true

con呼叫contains(object obj)的時候 ,集合判斷是否包含某個物件時,呼叫的是equals()方法,判斷內容,如果內容一樣返回true,否則返回false.

當然在呼叫自定義類的時候,需要對自定義類重寫equals()方法.詳情請看JavaSE第十二天的Contains注意事項.

con.add(newPerson("tom",12));

con.contains(newPerson("tom",12));//返回 false 如果不對Person重寫equals方法,這個會返回false,(con集合裡面明明有newPerson("tom",12)這個物件,用我們上面說的呼叫equals方法按道理是返回true的為啥結果會返回false呢?) 原因是自定義類沒有重寫equals()方法,直接呼叫系統(Object)的equals方法是不行的,該方法是比較地址的,這個時候去自定義類裡面source裡面右擊找到一個Generate hashCode()and equals()點選自動生成這個方法,hashCode()暫時不需要 自動會生成的,要不要無所謂.

 

List介面:是Collection的子介面,存放資料的特點 有序,可以出現重複元素,既然有序,就是可以對元素的下標進行儲存.

(1).ArrayList類:

是List的實現子類.其使用的資料儲存結構是陣列,特點:查改快,增刪慢,理解:之所以查改快,是因為陣列是根據下標index進行操作的,所以其查詢更改效率更高;

而相應的,要是對其進行增加和刪除,會在記憶體空間中重新開闢空間,因為陣列在一開始定義的時候就確定了記憶體大小.要是進行增加操作會開闢更大一點的空間,刪除操作同理.所以其增加刪除效率會低.

(2)LinkedList類:

也是List的實現子類.其使用的資料儲存結構是連結串列,特點:查改慢,增刪快,理解:之所以查改慢,是因為連結串列是沒有索引值進行快速的查詢,其要一個一個遍歷才可以對元素進行查詢或修改操作.

效率著實太慢.而相應的增刪快,只需要根據元素值增加或修改即可.不需要關心它放在那裡,放進去就行了,修改同理,這樣效率就很高.

Set介面:也是Collection的子介面,存放的資料是無序的,且不能出現重複的元素.

無序!=隨機 這裡的無序指的是元素在記憶體中的儲存位置是無序的

不可重複:就是當向集合中新增A和B元素的時候,如果A和B相等,A新增進去,B就不能新增進去了.

(1)HashSet類:其使用的資料結構是雜湊表 查詢慢 增刪快  查詢根據迭代器iterator一個一個查詢元素,而增刪是根據元素進行新增刪除的操作.效率較高.

對Set集合不可出現重複元素的說明:

Set set = new HashSet();

set.add("456");

set.add("123");

set.add(666);

set.add(new String("AA"));

set.add(new String("AA"));

 

set.add(new Dog("tom", 18)); //=====>>A

set.add(new Dog("tom", 18)); //=====>>B

System.out.println(set);

執行上面的程式碼結果如下圖


A新增進去了,B就新增不進去了,上圖結果顯示是可以新增進去的.(疑問:跟我們理解的set類不允許出現重複元素不是相矛盾嗎?)

提出疑問:Set集合是怎麼判斷兩個元素是否重複?

解答:是根據兩個方面進行判斷的,分別是hashCode()和equals()方法

首先先判斷hashCode()值,在判斷equals(),hashCode():每個物件都有一個雜湊值,然後根據雜湊值的不同,會把元素儲存到記憶體中不同的位置

hashCode()它的作用決定元素在記憶體中位置,方便根據雜湊值快速定位元素的記憶體位置,如果記憶體中沒有元素,則直接插入

如果不一樣直接插入,一樣在對equals()方法進行比較,,如果一樣就不插入,不一樣就插入.

以下例子為例:

Set set = new HashSet(); //其中HashSet可以有 LinkedHashSet 和TreeSet代替  但是TreeSet有個細節就是排序的問題後面再講,其自定義類要繼承 Comparable介面實現CompaerTo方法的重寫.

set.add("456");

set.add("123");

set.add(666);

 

set.add(newString("AA"));

booleancontains = set.contains(new String("AA"));

System.out.println(contains);

set.add(newString("AA"));

 

set.add(new Dog("tom", 18));

booleancontains2 = set.contains(new Dog("tom", 18));

System.out.println(contains2); //true

set.add(newDog("tom", 18));

System.out.println(set);

System.out.println("AA".hashCode());

System.out.println("AA".hashCode());

 

System.out.println(newDog("tom", 18).hashCode());

System.out.println(newDog("tom", 18).hashCode());

System.out.println(newDog("tom", 18).equals(new Dog("tom", 18)));

 

//上述沒有對Dog類hashCode()重寫但是對equals()重寫了.執行結果如下圖:


(一)對上述結果解釋如下:

①第一個true 因為String是系統類,系統已經對String重寫了hashCode()和equals()方法,我們只需知道equals方法重寫就行了 因為contains()用到的是equals()方法.

②第二個false 因為Dog類沒有對hashCode()方法重寫 紅色的newDog("tom", 18)的雜湊值跟橙色的new Dog("tom", 18)的雜湊值不一樣,所以判斷的結果是false

③第三個結果 為什麼我們肉眼看到的兩個相等的Dog元素為什麼可以新增進去,因為Dog類沒有重寫hashCode()方法,系統認為他們hashCode()是不一樣的,所以hashCode()不一樣第二個Dog元素就直接插入進去了.

④第四個結果 兩個String型別的AA的雜湊值都是2080,因為系統String類重寫了重寫了hashCode()和equals()方法,兩者的雜湊值肯定是一樣的.equals()得出的結果也是一樣的.(equals()執行結果看①).

⑤第五個結果true 因為Dog類重寫了equals()方法.

 

//上述對Dog類hashCode()重寫但是沒有對equals()重寫了.執行結果如下圖:


(二)對上述結果解釋如下:

①第一個true同(一)中的①.

②第二個false,雖然重寫了hashCode(),雜湊值一樣 比較equals()方法,但是Dog沒有重寫equals()方法,使用的Object(因為Object是所有類的父類)中的equals()方法,該equals()方法比較的是地址,很明顯new物件了 地址肯定不一樣所以是false.

③第三個結果 為什麼我們肉眼看到的兩個相等的Dog元素為什麼可以新增進去,雖然重寫hashCode()得到的方法是一樣的雜湊值,雜湊值一樣了還得比較equals()方法,但是equals()方法Dog沒有重寫呼叫父類的equals()方法,該equals()方法比較的是地址,也是new出來的物件,地址明顯不一樣,所以equals()得到的值也不一樣,所有第二個Dog元素就可以直接新增進去了.

④第四個結果  String()重寫了hashCode()方法和equals()方法 ,其雜湊值肯定是一樣的兩個2080.兩個116545同理String 因為Dog類重寫了hashCode()方法,所以其雜湊值是一樣的

⑤第五個結果false Dog類沒有重寫equals()方法,呼叫的是Object的equals()方法,該equals()方法比較的是地址,兩個new出來的物件地址肯定不一樣,所以結果false.

 

//上述對Dog類hashCode()和equals()都重寫了.執行結果如下圖:


(三)對上述結果解釋如下:

第一個true同(一)/(二)中的①;

第二結果true  Dog類重寫了hashCode()和equals()方法,紅色的newDog("tom", 18)上面的橙色的new Dog("tom", 18)得出的雜湊值和equals是一樣的,所有返回ture;

第三個結果 Dog類重寫了hashCode()和equals()方法,所以肉眼看到的兩個元素是一樣的這次通過重寫的hashCode()方法和equals方法()判斷的就真的是一樣的了.所有隻新增了其中一個元素.

第四個結果  String()重寫了hashCode()方法和equals()方法 ,其雜湊值肯定是一樣的兩個2080.兩個116545同理String 因為Dog類重寫了hashCode()方法,所以其雜湊值是一樣的

第五個結果 true Dog類重寫了equals()方法,所以是true.

(2)LinkedHashSet類 其儲存的資料結構是雜湊表+連結列表 查詢快,增刪慢 根據連結列表查詢較快 增刪要使用迭代器一個一個遍歷找到這個元素才可以刪除 .

雜湊表儲存結構將元素可以隨機放入記憶體中,連結列表維護了一個有序的儲存順序迭代的時候就按照連結列表中的順序去迭代正是有了連結列表的存在,所以元素插入的順序和取出的順序是一致的

迭代器:

//有error的會發生併發修改異常,你在使用迭代器和foreach()千萬不要修改集合的長度(不能刪不能新增),但是有ture的修改集合的長度(即增刪操作)不會發生併發異常.

/*for(Object object : source) {

//強轉資料型別

Bookbook=(Book) object;

if(book.getName().equals(name)){

source.remove(object);

}

}*/ //error 

 

for(int i = 0; i < source.size(); i++) {

Objectobject=source.get(i);

Bookbook=(Book) object;

if(book.getName().equals(name)){

source.remove(object);

}

}//true

 

/*        Iteratoriterator=source.iterator();

while(iterator.hasNext()) {

Bookbook = (Book) iterator.next();

if(book.getName().equals(name)){

//使用迭代器來做刪除操作

source.remove(book);

}

}* //error

 

/*ListIteratorlistIterator = source.listIterator();

while(listIterator.hasNext()) {

Bookbook = (Book) listIterator.next();

if(book.getName().equals(name)){

//使用迭代器來做刪除操作

listIterator.remove();

}

}*///true

 

(3)TreeSet類 無序不重複

TreeSet會對插入的元素進行排序

排序的依據?

①自然排序:依賴於元素的compareTo()方法,以為這compareTo只有中只有實現了compareTo方法才能排序

Integer String都實現了compareTo()方法排序,前提是Integer和String類繼承Comparable介面.

一個物件的CompareTo()、hashCode()、equals()結果應該一致.

以String為例:

 

以下面的程式碼為例:

Setset2=new TreeSet();

set2.add(newPerson("bb", 19));

set2.add(newPerson("cc", 20));

set2.add(newPerson("aa", 18));

set2.add(newPerson("aa", 2000));

如果沒有person類繼承Comparable介面實現CompareTo()方法會報這樣一個錯:

Exception in thread"main" java.lang.ClassCastException: com.lanou3g.setdemo.Personcannot be cast to java.lang.Comparable

Comparable是一個介面,其中只有一個方法那就是CompareTo()方法.要對其進行重寫

首先得繼承這個介面:如下圖


接著對方法進行重寫如下圖:


②定製排序

依賴TreeSet(TreeMap)自己構造的方法


下面這種方法是寫在一個方法裡面,然後在main方法裡面呼叫simpleMethod();

 

2.

一級介面:Map

Map介面,定義了所有Map下集合的公共方法;

特點:

①元素以key-vlaue的方式出現,鍵值對的方式

②Map中的元素也是無序的

③Map中的key值是唯一的,體現了元素不可重複性

如何遍歷Map集合?

 

//方式一:不建議使用

// 1.現獲取所有的key值

Setkeys = map.keySet();

//2.遍歷儲存所有的key值指的keys集合

for(Object key : keys) {

//根據key值獲取map中的values值

Objectvalue = map.get(key);

System.out.println(key+"=>"+value);

}

//方式二:建議使用

//entrySet()這個方法會返回一個Set集合,集合儲存的都是Entry物件

//這個物件中儲存的就是對應的一對鍵值對key和value值

 

SetentrySet = map.entrySet();

for(Object o : entrySet) {

Map.Entryentry=(Map.Entry) o;

System.out.println(entry.getKey()+"==>"+entry.getValue());

}

Map集合中新增元素和修改元素是同一方法.

根據key去修改value的值.

 

 

實現子類:HashMap類,LinkedHashMap類, TreeMap類

(1).HashMap類

同Map類

       (2).LinkedHashMap類:

       LinkednHashMap也是儲存的鍵值對,比著Map集合對出來個特點,它裡面儲存的內容是有序的,也是通過連結列表維護的,僅僅維護key值.

 

        (3).TreeMap類

同TreeSet類,其中key資料型別必須一致.

 

 

總結重點 :Set不可出現重複元素使用add()方法如何判斷兩個元素是否相等?

            TreeSet和TreeMap兩者排序方法的總結.

Set

向集合新增元素是先判斷有沒有這個元素 有新增進去,沒有新增失敗

Map

向集合新增元素是根據key值以一種覆蓋的形式新增(也可理解為修改的意思)因為Map新增元素和修改元素是同一種方法.

 

 

 

 

 

 

 

 

 

 

 

 

相關文章