程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Java集合(一):Java集合概述

Java集合(一):Java集合概述

編輯:JAVA綜合教程

Java集合(一):Java集合概述


1 概述

Java提供了一個豐富的集合框架,這個集合框架包含了許多接口、虛擬類和實現類。這些接口和類提供了豐富的功能,能夠滿足基本的聚合需求。下圖就是這個框架的整體結構圖:

\

可以看見,這個框架非常大,大到吃驚的地步。這個圖的左面部分是接口,右面部分是類,中間的線代表了右面的類實現了左面的哪些接口。比如,AbstractList類實現了List接口,那麼繼承自AbstractList類的子類都實現了這個接口。還有,如果一個類實現了一個接口,那麼這個類也實現了這個接口的所有父接口。比如,TreeSet類實現了Deque接口,那麼TreeSet類也實現了Queue接口、Collection接口和Iterable接口(接口Collection擴展了Iterable,這裡沒顯示出來)。

圖中紅色的類表示抽象類,大部分抽象類都以Abstract開頭,除了Dictionary。綠顏色的類表示遺留類,這些類在Java一開始的時候就已經存在了。

2 接口與實現分離

Java集合類庫中將接口(interface)與實現(implementation)分離。這裡以隊列(queue)為例。

隊列接口指出可以在隊列的尾部添加元素,在隊列的頭部刪除元素,並且可以查找隊列中的元素個數。即隊列中的元素按照先進先出的元素使用隊列。

如果我們設計queue的接口,可能這樣設計:

 

interface Queue
{
    void add(E element);
    E remove();
    int size();
}
這裡給出了三個基本的方法。這個接口沒有給出隊列應該是如何實現的。通常,隊列的實現方式有兩種:一個是使用循環數組,一個是使用鏈表。

 

使用循環數組時需要指出對頭head和隊尾tail;使用鏈表時也需要給出頭和尾:

 

class CircularArrayQueue implements Queue
{
    CircularArrayQueue(int capacity){...}
    public void add(E element){...}
    public E remove(){...}
    private E[] elements;
    private int head;
    private int tail;
}

class LinkedListQueue implements Queue
{
    LinkedListQueue(){...}
    public void add(E element){...}
    public E remove(){...}
    public int size(){...}
    private Link head;
    private Link tail;
}
上面的只是我們自己實現的簡單的隊列,Java類庫中沒有這兩個類。當需要使用隊列時,可以使用LinkedList類,這個類實現了Queue接口。

 

當在程序中使用隊列時,一旦構建了集合就不需要知道究竟使用了哪種實現。因此,只有在構建集合對象時,使用具體的類才有意義。可以使用接口類型存放集合的引用:

 

Queue employee=new CircularArrayQueue<>(100);
employee.add(new Employee("Harry"));
利用這種方式,一旦改變了想法,可以輕松地使用另一種不同的實現。只需要對程序的一個地方做出修改,即調用構造器的地方。如果覺得LinkedListQueue是個更好的選擇,就可以這樣修改:

 

 

Queue employee=new LinkedListQueue<>();
employee.add(new Employee("Harry"));
接口本身沒有給出具體的實現方式,因此也不能給出哪種實現更符合實際應用。這樣,選擇哪種實現方式就需要由程序員選擇。Java類庫中實現了很多的類,每個類都有各自的特性以及適用場景,也許選擇了某個實現方式在某個特性上更加優秀,但也可能在另一個特性上付出了代價。如何平衡好各個性能的代價,需要類庫使用者自己把握。

 

在上圖中,我們可以發現很多紅色的以Abstract開頭的類,這些類都是抽象類,這些類是為類庫的實現者設計的,這些類中實現了一些基本的方法。如果想要實現自己的隊列類,你會發現擴展AbstractQueue類比實現Queue接口更方便。

3 Java類庫中的集合接口和迭代器接口

在Java類庫中,集合類的基本接口是Collection接口。這個接口中有如下兩個方法:

 

boolean add(E element);
Iterator iterator();
當然,除了這兩個方法外還有其它的方法,會在後面介紹。

 

add方法用於向集合中添加元素,如果添加元素確實改變了集合就返回true,如果集合沒有發生變化就返回false。

iterator方法用於返回一個實現了Iterator接口的對象。可以使用這個迭代器對象依次訪問集合中的元素。

下面來介紹一下Java類庫中重要的迭代器。

Iterator迭代器接口有三個方法:

 

public interface Iterator
{
    E next();
    boolean hasNext();
    void remove();
}
通過反復調用next方法,可以逐個訪問集合中的每個元素。但是如果達到了集合的末尾,next方法將拋出一個NoSuchElementException異常。因此,在調用next方法之前應該調用hasNext方法。如果迭代器對象還有多個供訪問的元素,這個方法就返回true。因此,可以使用下面的方法訪問集合中的所有元素:

 

 

Collection c=...;
Iterator it=c.iterator();
while(it.hasNext())
{
    String element=it.next();
    do something with element
}
從Jave SE 5.0起,還可以使用for each循環訪問集合中的所有元素:

 

 

for(String element : c)
{
    do something with element
}
編譯器只是將這個for each循環翻譯為帶有迭代器的循環。

 

for each循環可以與任何實現了Iterable接口的對象一起工作,這個接口只包含一個方法:

 

public interface Iterable
{
    Iterator iterator();
}
Collection接口擴展了Iterable接口,所以對於標准庫中的任何集合都可以使用for each循環。

 

需要注意的是,元素被訪問的順序取決於集合的類型。如果對ArrayList進行迭代,迭代器將會從索引0開始,每迭代一次,索引值加1。然而,如果訪問HashSet中的元素,每個元素將會按照某種隨機的次序出現。雖然可以確定在迭代過程中能夠遍歷所有的元素,但卻無法預知元素被訪問的次序。

Java集合類庫中的迭代器與其它類庫中的迭代器在概念上有著重要的區別。C++的迭代器是根據數組索引建模的。如果給定這樣一個迭代器,就可以查看指定位置上的元素,就像知道數組索引i就可以查看數組元素a[i]一樣。不需要查找元素,就可以將迭代器向前移動一個位置。這與不需要執行查找操作就可以通過i++將數組索引向前移動一樣。但是,Java迭代器不是這樣操作的。查找操作和位置變更是緊密相連的。查找一個元素的唯一方法是調用next,而在執行查找操作的同時,迭代器的位置隨之向前移動。

即,可以將迭代器看做一個位置,這個位置在兩個元素之間。而next操作會改變這個位置。但調用next時,迭代器就越過下一個元素,並返回剛剛越過的那個元素的引用。

Iterator接口的remove方法用於刪除上次調用next方法返回時的元素。也就是說,remove操作和next操作具有依賴性,如果沒有調用next方法而調用remove方法是非法的,會拋出一個IllegalStateException異常。下面是刪除集合中的第一個元素:

 

Iterator it=c.iterator();
it.next();
it.remove();
如果刪除兩個相鄰的元素,下面的方法是錯誤的:

 

 

it.remove();
it.remove();
必須先調用next方法越過待刪除的元素:

 

 

it.remove();
it.next();
it.remove();
有一個不怎麼恰當的比喻,可以將迭代器看做光標:

 

 

Collection c=ArrayList<>();
c.add("a");
c.add("b");
c.add("c");
Iterator it=c.iterator();
這時,迭代器的位置如下:

 

| a b c

當調用next方法,光標就會後移,然後返回剛才越過的元素:

 

it.next();
此時,迭代器的位置如下:

 

a | b c

並返回元素a。

如果要刪除元素,刪除的行為就像後退鍵(Backspace)一樣,刪除光標後面(以右為前)的元素:

 

it.remove();
此時,迭代器的位置如下:

 

| b c

和後退鍵不同的是,如果迭代器的後面即使還有元素,沒有調用next方法也不能刪除。

由於Collection接口和Iterator接口都是泛型接口,可以編寫操作任何集合類型的實用方法。其實,Collection接口中有很多方法:

 

public interface java.util.Collection extends java.lang.Iterable {
  public abstract int size();
  public abstract boolean isEmpty();
  public abstract boolean contains(java.lang.Object);
  public abstract java.util.Iterator iterator();
  public abstract java.lang.Object[] toArray();
  public abstract  T[] toArray(T[]);
  public abstract boolean add(E);
  public abstract boolean remove(java.lang.Object);
  public abstract boolean containsAll(java.util.Collection);
  public abstract boolean addAll(java.util.Collection);
  public abstract boolean removeAll(java.util.Collection);
  public boolean removeIf(java.util.function.Predicate);
  public abstract boolean retainAll(java.util.Collection);
  public abstract void clear();
  public abstract boolean equals(java.lang.Object);
  public abstract int hashCode();
  public java.util.Spliterator spliterator();
  public java.util.stream.Stream stream();
  public java.util.stream.Stream parallelStream();
}
有很多的方法的含義都很明確,這裡不做過多的解釋。

 

當然,如果實現Collection接口的每一個類都要實現這些例行方法將是一件很煩人的事。為了能夠讓實現者更容易地實現這個接口,Java類庫提供了一個AbstractCollection類,在這個類裡提供了一些例行方法,這樣,一個具體的集合類就可以擴展AbstractCollection類而不需要實現所有的例行方法了,並可以覆蓋裡面的方法。

4 Java類庫中的接口

下圖給出了Java類庫中的所有接口:

\

其中,Collection和Map是集合框架的兩個主要接口,所有的集合類都實現了這兩個接口中的一個。Iterator接口和ListIterator接口是迭代器接口,而ListIterator接口提供了更豐富的操作,這個接口會在List列表中介紹。RandomAccess接口是一個標簽接口,也就是說這個接口沒有任何方法,但是可以用這個接口標注某個類,然後檢查一個類是否支持隨機訪問。

在隨後的介紹中,會詳細介紹這些接口的方法和使用。

5 Java類庫中的類

下面是Java類庫中的所有實現類:

\

其中紅顏色的是抽象類。可以明顯的分為兩個部分,一個集合(Collection),一個映射(Map)。

這些是常用的類,再加上一些專用的類,比如:EnumSet、LinkedHashSet、EnumMap、LinkedHashMap、IdentityHashMap和WeakHashMap,一共14類,它們的特點如下:

 

Java庫中的具體集合 集合類型 描述 ArrayList 一種可以動態增長和伸縮的索引序列 LinkedList 一種可以在任何位置進行高效插入和刪除操作的有序序列 ArrayDeque 一種用循環數組實現的雙端隊列 HashSet 一種沒有重復元素的無序集合 TreeSet 一種有序集 EnumSet 一種包含枚舉類型值的集 LinkedHashSet 一種可以記住元素插入順序的集 PriorityQueue 一種允許高效刪除最小元素的集合 HashMap 一種存儲鍵/值關聯的數據結構 TreeMap 一種鍵值有序排列的映射表 EnumMap 一種鍵值屬於枚舉類型的映射表 LinkedHashMap 一種可以記住鍵值項添加次序的映射表 WeakHashMap 一種其值無用武之地後可以被垃圾回收器回收的映射表 IdentityHashMap 一種使用==而不是equals比較鍵值的映射表

對於有序無序、元素可重復和元素不可重復,特點總結如下,注意,對於Map,考察的是鍵的值是否可重復:

\

6 更多

在後序的分析中,會給出這些具體類和集合的介紹:

2、Java集合(二):List列表

3、Java集合(三):Set集合

4、Java集合(四):Queue隊列

5、Java集合(五):專用Set和專用Map

6、Java集合(六):Java集合框架

7、Java集合(七):Java集合中的算法與遺留類

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved