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介面中定義的方法,子介面都有。
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。
繼承關係如下:
接下來我們詳細介紹一下這三個子類。
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)。