1. 程式人生 > >Java 集合類 1-Collection介面以及List子介面

Java 集合類 1-Collection介面以及List子介面

  在實際開發中,陣列的出現頻率並不高,因為陣列有一個很大的缺陷:陣列長度固定。所以從JDK1.2開始,為了解決Java陣列長度的問題,提供了動態的陣列實現框架——Java集合類框架。

  Java集合類框架實際上就是針對於資料結構的一種實現。

  在Java的集合類庫裡面(java.util)包含了兩個核心介面,Collection與Map。本次我們介紹的是Collection介面。

1. Collecion介面

  首先我們看一下JDK給出的Collection介面定義:

public interface Collection<E> extends Iterable
<E>

  Collection介面是一個泛型介面,可以很好的避免向下轉型時的ClassCastException異常。並且繼承了Iterable介面,繼承該介面的用途下面會講到。

  另外,Collection介面是儲存單個數據的集合最大父介面。即Collection集合每次只能儲存一個數據,這個資料可以是基本資料型別,自定義資料型別(自定義的類也可以),但每次只能儲存一個,不能一次儲存多個,但可以儲存多次啊。而且,實現Collection介面的子類也遵循該性質。

  Collection介面定義瞭如下常用方法:

// 返回集合長度
public int size();

// 集合是否為空,空返回true,反之false
public boolean isEmpty(); // 集合中是否包含指定元素 boolean contains(Object o); // 返回一個Iterator介面物件,用於集合的輸出,後面會講 Iterator<E> iterator(); // 將集合程式設計物件陣列返回 Object[] toArray(); // 將指定元素新增進集合中 boolean add(E e); // 在集合中刪除指定元素 boolean remove(Object o);

  雖然Collection介面定義瞭如此眾多的方法,但是在實際工程中我們並不會直接使用它,而是使用它的子介面List,Set。

  Colletion介面繼承關係如下:

Collection

  Collection介面中定義的方法,子介面都有。

2. List介面

  我們首先看看List介面的定義:

public interface List<E> extends Collection<E>

  在實際開發中,List介面的使用佔到了Collection集合系列的80%以上,在進行集合處理的時候,優先使用List介面。

  因為在List介面中定義了兩個很有用的擴充方法:

// 取得集合中指定下標的元素
E get(int index);

// 設定集合中指定下標元素
E set(int index, E element);

  List介面有三個常用子類,分別為ArrayList,Vector,LinkedList。

  繼承關係如下:

List介面

  接下來我們詳細介紹一下這三個子類。

2.1 ArrayList類(重要)

  ArrayList類可以新增重複的元素,也可以裝入空(null)。

  ArrayList是針對List介面的一個實現類,底層由陣列實現,對應資料結構中的順序表。因為它是Collection介面的實現類,所以自然是可以自動擴容,長度可變的。

  JDK給出的ArrayList類定義以及常用方法:

// 類定義
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

// List介面的擴充get方法
public E get(int index)

// List介面的擴充set方法
public E set(int index, E element)

  關於ArrayList類中方法的具體實現大家可以參考一下這篇文章:

  我們看下面的例子:

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

public class Test {
    public static void main(String[] args) {
        // 定義元素型別為String的ArrayList集合類
        List<String> list = new ArrayList<>();
        // 給集合類中新增元素,使用Collectio介面中定義的方法add
        list.add("hello");
        list.add("world");
        list.add("hello");
        list.add("java");
        list.add(null);
        // 這裡為了簡單起見,我們直接列印集合類,實際上,我們應該使用Iterator介面的物件進行集合類的輸出
        System.out.println(list);   
    }
}

執行結果:

執行結果

  這也證明了ArrayList可以新增重複元素和null。

  我們再測試一下ArrayList的其他方法

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

public class Test {
    public static void main(String[] args) {
        // 定義元素型別為String的ArrayList集合類
        List<String> list = new ArrayList<>();
        // 給集合類中新增元素,使用Collectio介面中定義的方法add
        list.add("hello");
        list.add("world");
        list.add("hello");
        list.add("java");
        list.add(null);

        // size()
        System.out.println("list size is : "+list.size());
        // isEmpty()
        System.out.println("list.isEmpty(): "+list.isEmpty());
        // remove()
        System.out.println("list.remove(): "+list.remove("world"));
        System.out.println("after remove [world] :"+list);
        // contains()
        System.out.println("list.contains(): "+list.contains("world"));

        // get()方法進行集合元素輸出
        System.out.println("print by list.get() :");
        for(int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
    }
}

執行結果:

執行結果

  另外注意一點的就是,我們宣告ArrayList的時候的格式為:

List<T> list = new ArrayList<>();

  最好不要採用:

Collection<T> list = new ArrayList<>();

  雖然ArrayList是Collection介面的實現子類,但是List接口裡對Collection介面進行了方法的擴充,而且這樣的轉換還要設計向下轉型,所以最好使用List介面進行ArrayList物件的接收。

  ArrayList集合類除了接收基本資料型別,也可以接收自定義資料型別,如下面的例子:

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

class Person {
    public int age;
    public String name;
    public Person(String name, int age) {
        super();
        this.age = age;
        this.name = name;
    }
    @Override
    public String toString() {
        return "[name: "+this.name+", age: "+this.age+"]";
    }
}

public class Test {
    public static void main(String[] args) {
        // 定義元素型別為String的ArrayList集合類
        List<Person> list = new ArrayList<>();
        // 給集合類中新增元素,使用Collectio介面中定義的方法add
        list.add(new Person("xucc", 10));
        list.add(new Person("lixx", 10));
        list.add(new Person("zhss", 10));

        // get()方法進行集合元素輸出
        System.out.println("print by list.get() :");
        for(int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

執行結果:

執行結果

  最後要注意一點:ArrayList類的remove,contains都呼叫了物件的equals方法,如果沒有覆寫equals至想要的效果,會導致這兩個方法無法判斷出指定的物件,導致結果出現偏差。

2.2 Vector類(使用較少)

  Vector類是JDK1.0提出的,而上面介紹了的ArrayList是JDK1.2提出的。它的定義如下:

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

  Vector類的的使用方法,底層實現形式都與ArrayList類一致,這裡就不做贅述了。但是在細節上,兩者還是有很大差距的:

  • ArrayList是非同步處理,效能更高。而Vector是同步處理,效能較低。
  • ArrayList是非執行緒安全,Vector是執行緒安全(Vector執行緒安全的手段非常暴力,即所有的方法全加鎖,為synchronized方法,雖然很安全,但這也導致了Vector效率極其低下)。
  • 在輸出形式上,ArrayLit支援Iterator,ListIterator,foreach三中輸出方式。Vector擁有這三種之外,還多了一種,Enumeration(列舉輸出)

  在以後使用的時候優先考慮ArrayList,因為其效能更高,實際開發時很多時候也是每個執行緒擁有自己獨立的集合資
源。如果需要考慮同步也可以使用concurrent包提供的工具將ArrayList變為執行緒安全的集合。

  雖然日常中Vector的出場率不高,但是它卻有一個很重要的子類——Stack類。

2.3 LinkedList類

  LinkedList的底層實現為雙鏈表,使用發發與ArrayList一模一樣。

  定義如下:

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

  ArrayList封裝的是陣列,LinkedList封裝的是連結串列。

  ArrayList的remove時間複雜度為O(n),效率較低,但是查詢一個元素get時間複雜度為O(1)。

  LinkedList的remove時間複雜度O(1),效率高,但是查詢一個元素get時間複雜度為O(n)。