JAVA集合一之集合簡介(Collection,List,Set)


  在編寫JAVA程序中,我們經常會遇到需要保存一組數據對象,此時,我們可以采用對象數組來進行多個對象的保存,但對象數組存在一個最大的問題即在於長度上的限制,如果說我們現在要保存一組對象,但是我們並知道數組對象到底有多少個的時候,那么此時就遇到了困難,因此為了解決此問題,在JDK1.2中,提出了類集框架的概念,並在JDK1.5中對此框架進行了修改,加入了泛型的支持,從而保證了操作的安全性。而在整個集合中,提供了幾個集合核心操作的接口,分別為:Collection、Set、List、Enumeration、Iterator、ListIterator等。

  1)單值保存的最大父接口:Collection

    所謂的單值保存指的是每次操作只保存一個對象,每次增加只增加一個對象,而在Collection接口之中定義了如下幾個常用的方法:

package com.njupt.study.collection;

import java.util.Iterator;

public interface Collection<E> extends Iterable<E>{

    /**
     * 增加數據
     * @param e
     * @return
     */
    boolean add(E e);
    /**
     * 刪除指定的元素
     * @param o
     * @return
     */
    boolean remove(Object o);
    /**
     * 清除數據
     */
    void clear();
    /**
     * 判斷集合是否為空
     * @return
     */
    boolean isEmpty();
    /**
     * 獲取元素的個數
     * @return
     */
    int size();
    /**
     * 查找一個數據是否存在
     * @param o
     * @return
     */
    boolean contains(Object o);
    /**
     * 將集合變為對象數組后返回
     * @return
     */
    Object[] toArray();
    /**
     * 將集合變為指定類型的對象數組
     * @param <T>
     * @param a
     * @return
     */
    <T> T[] toArray(T[] a);
    /**
     * 為Iterator接口實例化,來源於父類接口Iterable
     */
    Iterator<E> iterator();
    
}

 

 

 

  Collection接口本身在開發之中並不會直接的去使用,而在開發之中往往會使用兩個子接口:List、Set。

 

  2)允許重復的子接口:List

      List接口是Collection接口的子接口,是有序的 collection(也稱為序列)。此接口的用戶可以對列表中每個元素的插入位置進行精確地控制。用戶可以根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。

  public interface List<E>extends Collection<E>

      List接口對Collection接口進行了大量的擴充操作,而主要的擴充方法有如下幾個:

  

public interface List<E> extends Collection<E> {
    
     /**
      * 返回指定位置上的數據
      * @param index
      * @return
      */
     E get(int index);
     
     /**
      * 修改指定位置上的數據
      * @param index
      * @param element
      * @return
      */
     E set(int index, E element);
     
     /**
      * 為ListIterator接口實例化
      * @return
      */
     ListIterator<E> listIterator();
}
View Code

 

    List本身也是一個接口,所以如果要想使用這個接口就必須有子類,實現List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。

  1. ArrayList:

     在List接口里面ArrayList子類的使用幾率是最高的,一般List接口實例化,一般想到的為ArrayList。

     

 1 package com.njupt.study.collection;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 class Student
 7 {
 8     private String name;
 9     
10     private int age;
11 
12     public Student(){};
13     
14     public Student(String n,int a)
15     {
16         this.name = n;
17         this.age = a;
18     }
19     
20     public String getName() {
21         return name;
22     }
23 
24     public void setName(String name) {
25         this.name = name;
26     }
27 
28     public int getAge() {
29         return age;
30     }
31 
32     public void setAge(int age) {
33         this.age = age;
34     }
35     
36 }
37 
38 
39 public class Demo02 {
40 
41     public static void main(String[] args) {
42          List<Student> list  = new ArrayList<Student>();
43          
44          list.add(new Student("zhangsan",18));
45          
46          list.add(new Student("lisi",19));
47          
48          list.add(new Student("wangwu",17));
49          
50          System.out.println(list);
51          
52          System.out.println("******************");
53          
54          for(int i=0;i<list.size();i++)
55          {
56              System.out.println(list.get(i));
57          }
58     }
59 }
View Code

      輸出結果為:

     

[com.njupt.study.collection.Student@1fc4bec, com.njupt.study.collection.Student@dc8569, com.njupt.study.collection.Student@1bab50a]
******************
com.njupt.study.collection.Student@1fc4bec
com.njupt.study.collection.Student@dc8569
com.njupt.study.collection.Student@1bab50a

為了顯示更加明顯的信息,因此增加重寫toString()方法,

public String toString()
{
return this.name+"---->"+this.age;
}

顯示結果為:

[zhangsan---->18, lisi---->19, wangwu---->17]
******************
zhangsan---->18
lisi---->19
wangwu---->17

可以看見ArrayList采用的為數組方式保存元素對象。

add 為添加元素,那么remove 可以刪除元素,那么我們試試刪除元素:

 1 package com.njupt.study.collection;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 class Student
 7 {
 8     private String name;
 9     
10     private int age;
11 
12     public Student(){};
13     
14     public Student(String n,int a)
15     {
16         this.name = n;
17         this.age = a;
18     }
19     
20     public String getName() {
21         return name;
22     }
23 
24     public void setName(String name) {
25         this.name = name;
26     }
27 
28     public int getAge() {
29         return age;
30     }
31 
32     public void setAge(int age) {
33         this.age = age;
34     }
35     
36     public String toString()
37     {
38         return this.name+"---->"+this.age;
39     }
40 }
41 
42 
43 public class Demo02 {
44 
45     public static void main(String[] args) {
46          List<Student> list  = new ArrayList<Student>();
47          
48          list.add(new Student("zhangsan",18));
49          
50          list.add(new Student("lisi",19));
51          
52          list.add(new Student("wangwu",17));
53          
54          System.out.println(list);
55          
56          System.out.println("******************");
57          
58          for(int i=0;i<list.size();i++)
59          {
60              System.out.println(list.get(i));
61          }
62          
63          System.out.println("*********刪除元素*************");
64          
65          list.remove(new Student("wangwu",17));
66          for(int i=0;i<list.size();i++)
67          {
68              System.out.println(list.get(i));
69          }
70          
71     }
72 }
View Code

輸出結果為:

[zhangsan---->18, lisi---->19, wangwu---->17]
******************
zhangsan---->18
lisi---->19
wangwu---->17
*********刪除元素*************
zhangsan---->18
lisi---->19
wangwu---->17

可以看見元素並沒有被刪除,為什么呢?  那我們試試非自定義對象是否可以刪除呢?

 1 package com.njupt.study.collection;
 2 
 3 import java.util.ArrayList;
 4 
 5 public class Demo01 {
 6 
 7     /**
 8      * @param args
 9      */
10     public static void main(String[] args) {
11         java.util.List<String> list =  new ArrayList<String>();
12         
13         list.add("a");
14         
15         list.add("b");
16         
17         list.add("c");
18         
19         System.out.println(list);    
20         
21         for (int x = 0; x < list.size(); x++) {
22             System.out.println(list.get(x));
23         }
24 
25         list.remove("c");
26         
27         System.out.println("**********************");
28         
29         for (int x = 0; x < list.size(); x++) {
30             System.out.println(list.get(x));
31         }
32     }
33 
34 }
View Code

顯示結果為:

[a, b, c]
a
b
c
**********************
a
b

我們發現是可以刪除的,為什么我們自己定義的不能刪除呢?我們看下String的源碼有什么不同?

 public boolean equals(Object anObject) {
	if (this == anObject) {
	    return true;
	}
	if (anObject instanceof String) {
	    String anotherString = (String)anObject;
	    int n = count;
	    if (n == anotherString.count) {
		char v1[] = value;
		char v2[] = anotherString.value;
		int i = offset;
		int j = anotherString.offset;
		while (n-- != 0) {
		    if (v1[i++] != v2[j++])
			return false;
		}
		return true;
	    }
	}
	return false;
    }

  原因應該就是上面的,因為對象在刪除的時候,需要判斷集合中的對象和要刪除的對象是否一致,然后才能刪除,但我們自定義對象中,並沒有重寫equals方法所以,刪除的時候沒有成功,為此,我們增加equals方法試試如何?

 1 public boolean equals(Object obj)
 2     {
 3        if(this == obj)
 4        {
 5            return true;
 6        }
 7        
 8        if(obj == null)
 9        {
10            return false;
11        }
12        
13        if( ! (obj instanceof Student) )
14        {
15            return false;
16        }
17        
18        Student other = (Student) obj;
19        
20        if(this.name.equals(other.name) && this.age == other.age)
21        {
22            return true;
23        }
24        return false;        
25     }
View Code

     顯示結果為:

     

[zhangsan---->18, lisi---->19, wangwu---->17]
******************
zhangsan---->18
lisi---->19
wangwu---->17
*********刪除元素*************
zhangsan---->18
lisi---->19

已成功刪除。

注意:

既然ArrayList類可以為List接口實例化,那么也就可以為Collection接口實例化,但是這個時候已經不可以繼續使用get()方法操作了,所以此時只能夠將Collection變為對象數組后返回。

package com.njupt.study.collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

class Student
{
    private String name;
    
    private int age;

    public Student(){};
    
    public Student(String n,int a)
    {
        this.name = n;
        this.age = a;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
    
    public boolean equals(Object obj)
    {
       if(this == obj)
       {
           return true;
       }
       
       if(obj == null)
       {
           return false;
       }
       
       if( ! (obj instanceof Student) )
       {
           return false;
       }
       
       Student other = (Student) obj;
       
       if(this.name.equals(other.name) && this.age == other.age)
       {
           return true;
       }
       return false;        
    }
    
    /*public boolean equals(Object obj) {
        if (this == obj) {
            return true ;
        }
        if (obj == null) {
            return false ;
        }
        if (! (obj instanceof Student)) {
            return false ;
        }
        Student t = (Student) obj ;
        if(this.name.equals(t.name ) && this.age == t.age) {
            return true ;
        }
        return false ;
    } */

    
    public String toString()
    {
        return this.name+"---->"+this.age;
    }
}


public class Demo02 {

    public static void main(String[] args) {
         Collection<Student> list  = new ArrayList<Student>();
         
         list.add(new Student("zhangsan",18));
         
         list.add(new Student("lisi",19));
         
         list.add(new Student("wangwu",17));
         
         System.out.println(list);
         
         System.out.println("******************");
         
         Student[] all = list.toArray(new Student[]{});
         
         for(int i=0;i<all.length;i++)
         {
             System.out.println(all[i]);
         }
         
    }
}
View Code

 

 

     2. LinkedList

     同樣實現List接口的LinkedList與ArrayList不同,ArrayList是一個動態數組,而LinkedList是一個雙向鏈表。所以它除了有ArrayList的基本操作方法外還額外提供了insert方法在LinkedList的首部或尾部。

     由於實現的方式不同,LinkedList不能隨機訪問,它所有的操作都是要按照雙重鏈表的需要執行。在列表中索引的操作將從開頭或結尾遍歷列表(從靠近指定索引的一端)。這樣做的好處就是可以通過較低的代價在List中進行插入和刪除操作。

     與ArrayList一樣,LinkedList也是非同步的。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List: 
List list = Collections.synchronizedList(new LinkedList(…));

     ArrayList擅長於隨機訪問。同時ArrayList是非同步的。

 

     3. Vector

     Vector類是在JDK 1.0的時候所推出的最早的實現數據結構支持的類,其最早翻譯為向量,但是到了JDK 1.2之后,為了使其可以繼續使用,所以讓這個類多實現了一個List接口,這樣一來,就造成了Vector子類的操作方法比ArrayList更多,但是一般這些多的方法很少考慮。

      與ArrayList相似,但是Vector是同步的。所以說Vector是線程安全的動態數組。它的操作與ArrayList幾乎一樣。

 

      4.Stack

      Stack繼承自Vector,實現一個后進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop 方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。Stack剛創建后是空棧。

 

ArrayList和Vector的區別:

ArrayList和Vector都屬於List接口的常用子類,這兩者在操作形式以及概念上的區別如下:

No.

區別點

ArrayList

Vector

1

推出時間

JDK 1.2時推出,屬於新的類

JDK 1.0時推出,屬於舊的類

2

性能

使用異步處理方式,性能較高

采用同步處理操作,性能相對較低

3

安全性

非線程安全

線程安全

4

輸出

 

 

         因為Java主要從事於網絡的開發,所以使用異步的處理操作形式要比使用同步(Synchronized)更多。

 

  3)不允許重復的子接口:Set

      Set接口與List接口最大的不同在於里面的數據不允許有重復,那么首先觀察一下Set接口的繼承結構:

public interface Set<E>
extends Collection<E>

         Set是一種不包括重復元素的Collection,與List一樣,它同樣運行null的存在但是僅有一個。由於Set接口的特殊性,所有傳入Set集合中的元素都必須不同,同時要注意任何可變對象,如果在對集合中元素進行操作時,導致e1.equals(e2)==true,則必定會產生某些問題。實現了Set接口的集合有:EnumSet、HashSet、TreeSet。

          1.EnumSet

           是枚舉的專用Set。所有的元素都是枚舉類型。

           2.HashSet

            哈希(Hash)是一種數據的排列算法,這種算法的典型操作就是加塞算法,那塊有地就保存,所以只要帶有hash都是無序的。HashSet堪稱查詢速度最快的集合,因為其內部是以HashCode來實現的。它內部元素的順序是由哈希碼來決定的,所以它不保證set 的迭代順序;特別是它不保證該順序恆久不變。

 1 package com.njupt.study.collection;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 public class Demo03 {
 7 
 8     /**
 9      * @param args
10      */
11     public static void main(String[] args) {
12         Set<String> all = new HashSet<String>();
13         all.add("Hello");
14         all.add("World");
15         all.add("Hello"); // 重復數據
16         System.out.println(all);
17     }
18 
19 }
View Code

輸出結果為:

[World, Hello]

通過本程序可以發現,里面所保存的順序改變,而且如果有重復的數據也不能夠保存。

          3.TreeSet

          在TreeSet子類里面所有保存的數據是沒有重復的,而且可以為用戶自動的進行排序。基於TreeMap,生成一個總是處於排序狀態的set,內部以TreeMap來實現。它是使用元素的自然順序對元素進行排序,或者根據創建Set 時提供的 Comparator 進行排序,具體取決於使用的構造方法。

關於排序的說明:既然在TreeSet中的所有數據都可以排序,而且里面設置的數據也都是對象,那么下面就使用自定義類完成。

但是這個時候必須注意到一點:對於現在的TreeSet子類而言,由於其要對一組對象進行排序,那么這個對象所在的類就一定要實現Comparable接口,用於指定排序規則;

 1 package com.njupt.study.collection;
 2 
 3 import java.util.Set;
 4 import java.util.TreeSet;
 5 
 6 
 7 class Student implements Comparable<Student>
 8 {
 9     private String name;
10     
11     private int age;
12 
13     public Student(){};
14     
15     public Student(String n,int a)
16     {
17         this.name = n;
18         this.age = a;
19     }
20     
21     public String getName() {
22         return name;
23     }
24 
25     public void setName(String name) {
26         this.name = name;
27     }
28 
29     public int getAge() {
30         return age;
31     }
32 
33     public void setAge(int age) {
34         this.age = age;
35     }
36     
37     
38     public boolean equals(Object obj)
39     {
40        if(this == obj)
41        {
42            return true;
43        }
44        
45        if(obj == null)
46        {
47            return false;
48        }
49        
50        if( ! (obj instanceof Student) )
51        {
52            return false;
53        }
54        
55        Student other = (Student) obj;
56        
57        if(this.name.equals(other.name) && this.age == other.age)
58        {
59            return true;
60        }
61        return false;        
62     }
63 
64     
65     public String toString()
66     {
67         return this.name+"---->"+this.age;
68     }
69 
70     @Override
71     public int compareTo(Student o) {
72         if (this.age > o.age) {
73             return 1;
74         } else if (this.age < o.age) {
75             return -1;
76         } else {
77             return this.name.compareTo(o.name);
78         }
79     }
80 }
81 
82 public class Demo04 {
83 
84     /**
85      * @param args
86      */
87     public static void main(String[] args) {
88         Set<Student> all = new TreeSet<Student>();
89         all.add(new Student("張三",20)) ;
90         all.add(new Student("李四",19)) ;
91         all.add(new Student("王五",22)) ;    // 年齡一樣
92         all.add(new Student("趙六",22)) ;    // 年齡一樣
93         all.add(new Student("孫七",25)) ;
94         all.add(new Student("孫七",25)) ;    // 插入了重復的數據
95         all.remove(new Student("李四",19)) ;    // 刪除一個數據 
96         System.out.println(all);
97     }
98 
99 }
View Code

顯示結果為:[張三---->20, 王五---->22, 趙六---->22, 孫七---->25]

需要注意:

實現了對自定義類對象的排序,並且可以判斷重復元素,但是TreeSet類只是利用了Comparable完成了重復元素的判斷,可是這種判斷並不是真正意義上的重復元素判斷。

如果說現在要想判斷一個對象是否重復,嚴格來講,這個操作是由Object類所提供的,在任何一個子類里面需要覆寫Object類中的以下兩個方法;

                  · 對象比較:public boolean equals(Object obj);

                  · 對象編碼:public int hashCode();

         hashCode()方法是用於進行對象編碼計算的操作方法,如果要想進行對象的編碼,那么肯定需要一些數學上的支持,這里就不詳細講解了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM