1. 程式人生 > >Java學習之容器上(Collection介面常用方法,Iterator介面,使用foreach迴圈遍歷Collection集合元素,Set集合通用知識(Hashset類,hashcode()與Lin

Java學習之容器上(Collection介面常用方法,Iterator介面,使用foreach迴圈遍歷Collection集合元素,Set集合通用知識(Hashset類,hashcode()與Lin

1.容器API的類圖結構如下:

JAVA的集合類是一種特別有用的工具類,它可以用於儲存數量不等的多個物件,並可以實現常用資料結構,如棧,佇列等,除此之外,JAVA集合還可用於儲存具有對映關係的關聯陣列。

JAVA的集合大致上可分為:Set,List和Map三種體系,其中Set代表無序,不可重複的集合;List代表有序,重複的集合,而Map則代表具有遇敵關係的集合。Queue體系集合,代表一種佇列集合實現。

JAVA集合概述:

 JAVA提供集合類主要負責儲存盛裝其他資料,因此集合類也被稱為容器類。所有集合類都位於java.util包下。

JAVA集合類主要由兩個介面派生而出:Collection和Map,也是根介面。

Map儲存的每項資料都是key-value對,也就是由key和value兩個值組成。

下面給個比喻,再給個圖就非常容易理解了。

JAVA的所有集合分成三大類,其中Set 集合類似於一個罐子,把一個物件新增到Set集合時,Set集合無法記住新增這個元素的順序,所以Set裡的元素不能重複(否則系統無法準確識別這個元素)

List集合非常像一個數組,它可以記住每次新增元素的順序,只是List長度可變。

Map集合也像一個罐子,只是它裡面的每項資料都由兩個值組成。

如果訪問List集合中的元素,可以直接根據元素的索引來訪問,如果需要訪問Map集合中的元素,可以根據每項元素的key來訪問其value,如果希望訪問Set集合中的元素,則只能根據元素本身來訪問(這也是Set集合裡元素不允許重複的原因)

對於Set,List和Map三種集合,最常用的實現類,分別是HashSet,ArrayList  ,,HashMap  三個實現類。

1.1 Collection介面:

Collection介面——定義了存取一組物件的方法,其子介面Set和List分別定義了儲存方式。

(1)Set中的資料物件沒有順序且不可以重複。

(2)List中的資料物件有順序且可以重複。

Collection介面所定義的方法:

方法

描述

Boolean add(Object o)

向集合中新增一個物件的引用

Void clear()

刪除集合中的所有物件,即不再持有這些物件的引用

Boolean contains(Object o)

判斷在集合中是否持有特定物件的引用

Boolean isEmpty()

判斷集合是否為空

Iterator iterator()

返回一個Iterator物件,可用它來遍歷集合中的元素

Boolean remove(Object o)

從集合中刪除一個物件的引用

 Boolean retainAll(Collection<?> c)

保留集合中的指定內容 

Int size()

返回集合中元素的數目

Object[] toArray()

返回一個數組,該陣列包含集合中的所有元素

Boolean equals(Object o)

物件比較

Int hashCode() 

返回hash碼

 注意:相等的物件應該具有相等的 hash codes。容器類物件在呼叫remove,contains等方法時需要比較物件是否相等,這回涉及到物件型別的equals方法和hasCode方法;對於自定義的型別,需要重寫equals和hashCode方法以實現自定義的物件相等規則。

 Set介面和list介面都繼承了Collection介面,而map介面沒有繼承Collection介面,因此可以對set物件和list物件呼叫以上方法,但是不能對Map物件呼叫以上方法。

Collection介面的iterator()和toArray()方法都用於獲取集合中的所有元素,前者返回一個Iterator物件,後者放回一個包含集合中所有元素的陣列。

增加Name類的equals和hashCode方法如下:

複製程式碼
1 public boolean equals(Object obj){
2     if(obj instanceof Name){
3         Name name=(Name)obj;    return(firstName.equals(name.firstName)&&lastName.equals(name.lastName));
4 } 5 return super.equals(obj); 6 } 7 public int hashCode(){ 8 return firstName.hashCode(); 9 }
複製程式碼

方法應用例子:

複製程式碼
 1 import java.util.ArrayList;
 2 import java.util.Collection;
 3 import java.util.HashSet;
 4 public class TestCollection{
 5     public static void main(String[] args){
 6         Collection c= new ArrayList();
 7         c.add("孫悟空");
 8         c.add(6);
 9         System.out.println("c集合的元素的個數為:"+c.size());
10         System.out.println("c集合裡面是否包含孫悟空字元"+" "+c.contains("孫悟空"));
11         c.add("世界你好");
12         System.out.println("c集合裡面的元素:"+c);
13         Collection books=new HashSet(); //HashSet不允許元素重複。
14         books.add("世界你好");
15         books.add("你好世界");
16         System.out.println("c集合裡面是否完全包含books:"+c.contains(books));
17         c.removeAll(books);
18         System.out.println("c集合中的元素:"+c);
19         c.clear();
20         System.out.println("c集合裡面的元素:"+c);
21         books.retainAll(c);
22         System.out.println("books集合的元素:"+books);
23         
24     }
25 }
複製程式碼

 輸出結果:

c集合的元素的個數為:2
c集合裡面是否包含孫悟空字元 true
c集合裡面的元素:[孫悟空, 6, 世界你好]
c集合裡面是否完全包含books:false
c集合中的元素:[孫悟空, 6]
c集合裡面的元素:[]
books集合的元素:[]

 1.2 Iterator介面:

使用Iterator介面遍歷集合元素,Iterator介面是JAVA集合框架的成員,也被稱為迭代器。

Iterator介面中聲明瞭如下方法:

 boolean hashNext():如果迭代的集合元素還沒被遍歷,則返回true

Object next():返回集合裡下一個元素。

Void remove():刪除集合裡上一次next方法返回的元素。

複製程式碼
 1 import java.util.Collection;
 2 import java.util.HashSet;
 3 import java.util.Iterator;
 4 public class TextIterator {
 5     public static void main(String[] args){
 6     Collection books=new HashSet();            //無序序列,元素不可重複
 7     books.add("世界你好");
 8     books.add("你好世界");
 9     books.add("你好Java");
10     System.out.println("現在結合的元素:"+books);
11     Iterator it=books.iterator();        //獲取books集合對應的迭代器。
12     while(it.hasNext()){
13         String book=(String)it.next();    //it.next()方法返回的資料型別是object型別,需要強制型別轉換。
14         System.out.println(book);
15         if(book.equals("你好世界")){
16             it.remove();                //從集合中刪除上一次next方法返回的元素。
17         }
18         book="測試字串";                    //對book變數賦值,不會改變集合元素本身。
19     }
20     System.out.println(books);
21     
22     
23     }
複製程式碼

 輸出結果:

現在結合的元素:[世界你好, 你好Java, 你好世界]
世界你好
你好Java
你好世界
[世界你好, 你好Java]

Iterator僅用於遍歷集合,Iterator本身並不提供盛裝物件的能力,如果需要建立Iterator物件,則必須有一個被迭代的集合。

Iterator必須依附於Collection物件,有一個Iterator物件,則必然有一個懷之關聯的Collection物件。Iterator提供了2個方法來迭代訪問Collection集合裡的元素。

結論:當使用Iterator對集合元素進行迭代時,Iterator並不是把集合元素本身傳給了迭代變數,而是把集合元素的值傳給了迭代變數,所以修改迭代變數的值對集合元素本身沒有任何改變。

1.3使用foreach迴圈遍歷集合元素

我們知道,除了可以使用Iterator類迭代訪問Collection集合裡的元素之外,現在還可以使用foreach迴圈來迭代訪問集合元素會更加便捷。

foreach的語句格式: for(元素型別t 元素變數x : 遍歷物件obj){      引用了x的java語句; } 複製程式碼
 1 import java.util.Collection;
 2 import java.util.HashSet;
 3 
 4 public class TextForeach {
 5     public static void main(String[] args){
 6         Collection books=new HashSet();
 7         books.add("世界您好");
 8         books.add("您好世界");
 9         books.add("您好JAVA");
10         for(Object obj:books){
11             String book=(String)obj;            //此處的book變數也不是集合元素本身
12             System.out.println(book);
13             if(book.equals("您好世界")) {
14                 books.remove(book);
15             }
16 
17          }
18 
19           System.out.println(books);
20 
21     }        
複製程式碼

輸出結果:

現在結合的元素:[世界你好, 你好Java, 你好世界]
世界你好
你好Java
你好世界
[世界你好, 你好Java]

1.4 Set集合的通用知識:

1.4.1HashSet類:

HashSet是Set介面的典型實現,大多數時候使用Set集合時就是使用這個實現類。HashSet按Hash演算法一儲存集合中的元素,因此具有很好的存取和查詢效能。

特點:

》不能保證元素的排列順序,順序有可能發生變化。

》HashSet來是同步的,如果多個執行緒同時訪問一個Set集合,如果多個執行緒同時訪問一個HashSet,如果有2條或者2條以上執行緒同時修改了HashSet集合,必須通過程式碼來保證其同步。

》集合元素值可以是Null

我們可以簡單的認為:HashSet集合判斷兩個元素相等的標準是兩個物件通過equals方法比較相等,並且兩個物件的hashCode()方法返回值也相等。

複製程式碼
 1 import java.util.*;
 2 class A{                    //類A的equals方法總是返回true,但沒有重寫其hashCode()方法
 3     public boolean equals(Object obj){
 4         return true;
 5     }
 6 }
 7 class B{                    //類B的hashCode()方法總是返回l,但沒有重寫equals()方法
 8     public int hashCode(){
 9         return 1;
10      }
11 }
12 class C{                    //類C的hashCode()方法總是返回2,重寫其equals()方法
13     public int hashCode(){
14         return 2;
15     }
16      public boolean equals(Object obj){
17          return true;
18      }
19  }
20 public class TextHashset{
21         public static void main(String[] args){
22         HashSet books = new HashSet();
23         books.add(new A());
24         books.add(new A());
25         books.add(new B());
26         books.add(new B());
27         books.add(new C());
28         books.add(new C());
29 30         }
31 }
複製程式碼

我們從編譯結果可以看出,即使2個A物件通過equals比較返回true,但HashSet依然把它們當成2個,即使2個B物件的hashCode()返回相同值(都是1)但,HashSet依然把它們當成2個物件。

簡單的提醒點:

如果需要某個類的物件儲存到HashSet集合中,重寫這個類的equals()方法和hashCode()方法時,應該儘量保證兩個物件通過equals比較返回true時,它們的hashCode方法返回值也相等。

HashSet採用每個元素的hashCode作為其索引,從而可以自由增加HashSet的長度,並可以根據元素的hashCode值來訪問該元素。

(我們可以理解為相當於數組裡的下標索引)。

因為hashCode()方法很重要,看看重寫hashCode()方法的基本規則。

》當兩個物件通過equals方法比較返回true時,這個兩個物件的hashCode應該相等。

》物件中用作equals比較標準的屬性,都應該用來計算hashCode值。

複製程式碼
 1 import java.util.Iterator;
 2 
 3 class R{
 4     int count;
 5     public R(int count){
 6         this.count=count;
 7     }
 8     public String toString(){
 9         return "R[count"+count+"]";
10     }
11     public boolean equals(Object obj){
12         if(obj instanceof R){
13             R f=(R)obj;
14             if(f.count==this.count){
15                 return true;
16             }
17         }
18         return false;
19     }
20     public int hashCode(){
21         return this.count;
22     }
23 }
24 public class TestHashSet2{
25     public static void main(String[] args){
26         HashSet hs=new HashSet();
27         hs.add(new R(5));
28         hs.add(new R(-3));
29         hs.add(new R(9));
30         hs.add(new R(-2));
31         System.out.println("第1個hs,集合中的元素:"+hs+"\n");            //列印HashSet集合,集合元素沒有重複
32         Iterator it=hs.iterator();
33         R first = (R)it.next();
34         first.count = -3;                                        //為第一個元素的count例項變數賦值
35         System.out.println("第2個hs,集合中的元素:"+hs+"\n");
36         hs.remove(new R(-3));                                    //刪除count為-3的R物件
37         System.out.println("第3個hs,集合中的元素:"+hs+"\n");            
38         System.out.println("hs是否包含count為-3的R物件?"+hs.contains(new R(-3)));        //輸出false        
39           System.out.println("hs是否包含count為5的R物件"+hs.contains(new R(5)));         //輸出false    
40     }
41 }
複製程式碼

輸出結果:

第1個hs,集合中的元素:[R[count5], R[count9], R[count-3], R[count-2]]

第2個hs,集合中的元素:[R[count-3], R[count9], R[count-3], R[count-2]]

第3個hs,集合中的元素:[R[count-3], R[count9], R[count-2]]

hs是否包含count為-3的R物件?false
hs是否包含count為5的R物件false

ps:

(1)object類中的hashcode()方法比較的是物件的地址(引用地址),使用new方法建立物件,兩次生成的當然是不同的物件,造成的結果就是兩個物件的hashcode()返回的值不一樣。所以hashset會把new方法建立的兩個它們當作不同的物件對待,

(2)在java的集合中,判斷兩個物件是否相等的規則是: 
a),判斷兩個物件的hashCode是否相等 
      如果不相等,認為兩個物件也不相等,完畢 
      如果相等,轉入2) 
(這一點只是為了提高儲存效率而要求的,其實理論上沒有也可以,但如果沒有,實際使用時效率會大大降低,所以我們這裡將其做為必需的。) 
b),判斷兩個物件用equals運算是否相等 
      如果不相等,認為兩個物件也不相等 
      如果相等,認為兩個物件相等(equals()是判斷兩個物件是否相等的關鍵) 

LinkedHashSet類:

HashSet還有一個子類LinkedHashSet,它也是根據元素hashCode值來決定元素儲存位置,它是需要維護元素的插入順序,因此效能略低於HashSet的效能,但在迭代訪問Set裡的全部元素時將有很好的效能,因為它以連結串列來維護內部順序。

複製程式碼
 1 import java.util.LinkedHashSet;
 2 public class LinkedHashSetTest{
 3     public static void main(String[] args){
 4         LinkedHashSet  books = new LinkedHashSet();
 5         books.add("世界您好");
 6         books.add("您好世界");
 7         System.out.println(books);     
 8         books.remove("世界您好");            //刪除世界您好   
 9         books.add("世界您好");            //重新新增世界您好
10         System.out.println(books);
11     }
12 }
複製程式碼

 輸出結果:

[世界您好, 您好世界]
[您好世界, 世界您好]

編譯結果相信大家都理解,因為元素的順序正好與新增順序一致。

from: http://www.cnblogs.com/shide/archive/2013/03/30/2982755.html