Java類集框架

在基礎應用中,通常我們可以通過數組來保存一組具有相同屬性的對象或者基本類型的數據,但使用數組的弊端在于其大小不可更改,出于靈活性考慮,可以使用鏈表來實現動態的數組。任何事情具有兩面性,靈活性的代價就是操作上的繁瑣。在計算機世界里,處理繁瑣問題的常用方法就是將其封裝,只向外提供可調用方法的視圖。Java類集框架就是對這一方法的一種官方實現一套動態對象數組的操作類。本質上,Java類集框架就是Java對數據結構的一個大體上的封裝。
在java.util包中定義了所有與類集有關的操作接口:Collection,List,Set,Map,Iteraror,ListIterator,Enumeration。

在Java中,每個變量都有其所屬的數據類型,要么是基本數據類型(int,float,char等)要么是自定義的數據類型--即類。而泛型的本質就是將變量”的類型”參數化,也就是說所操作的數據類型被指定為一個參數這種參數類型可以用在類,接口和方法的創建中,分別稱為泛型類,泛型接口,泛型方法。



類集接口

接口 描述
Collection 能操作一組對象,他位于類集層次結構的頂層
List 擴展Collection支持處理序列(對象的列表)
Set 擴展Collection支持處理集合,集合元素必須唯一
SortedSet 擴展Set支持處理序列集合

在這些接口中定義了操作該類集的一些方法。支持這些方法的類集被稱為可修改的(modifiable)。不允許修改其內容的類集被稱為不可修改的(unmodifiable)。而所有內置的類集都是可修改的。如果對一個不可修改的類集使用這些方法,將引發一個UnsupportedOperationExcepation異常



單值保存的最大父接口--Collection

Collection接口是構造類集框架的基礎,是單值數據操作的最大父接口它聲明了所有類集都將擁有的核心方法。所有類集均實現Collection。其中有幾種方法可能會引發一個UnsupportedOperationExcepation異常。這些異常將發生在修改不能被修改的類集的時候。當一個對象與另一個對象不兼容,例如企圖增加一個不兼容的對象到一個類集中時,將產生一個ClassCastException異常。

方法 描述
boean add(Object obj) 將obj加入到調用類集中。如果obj被加入到類集中了,則返回true;如果此collection不允許有重復元素,并且已經包含了obj,則返回false
boolean addALL(Collection c) 將c中所有元素都加入到調用類集中,如果操作成功(元素被加入了),則返回true,否則返回false
void clear( ) 從調用類集中刪除所有元素
boolean contains(Obiect obj) 如果obj是調用類集的一個元素,則返回true,否則返回false
boolean containsALL(Collection c) 如果調用類集包含了c中的所有元素,則返回true,否則返回false
boolean equals(Object obj) 如果調用類集與obj相等,則返回true,否則返回false
int hashCode( ) 返回調用類集的hash(哈希)值
boolean isEmpty( ) 如果調用類集是空的,則返回true,否則返回false
Iterator iterator( ) 返回調用類集迭代器
boolean remove(Object obj) 從調用類集中刪除obj的一個實例。如果這個元素被刪除了則返回true,否則返回false
boolean removeALL(Collection c) 從調用類集中刪除c的所有元素。如果類集被改變了(也就是說元素被刪除了),則返回true,否則返回false
boolean retainALL(Collection c) 刪除調用類集中除了包含在c中的元素之外所有元素,如果類集被改變了(也就是說元素被刪除了),則返回true,否則返回false。
int size( ) 返回調用類集中元素的個數
Object[ ] toArray( ) 返回一個數組,該數組包含了所有存儲在調用類集中的元素。數組元素是類集元素的備份
Object[ ] toArray(Object array[ ]) 返回一個數組,該數組僅僅包含了那些類型與數組元素類型匹配的類集元素。數組元素是類集元素的備份。如果array的大小與匹配元素的個數相等,它們被返回到array。如果的大小比匹配元素的個數小,將分配并返回一個所需大小的新數組。如果array的大小比匹配元素的個數大,在數組中,在類集元素之后的單元被置為null。如果任一類集元素的類型都不是array的子類型,則引發ArrayStoreException異常

在Collection接口中所提供的方法一定是日后進行程序開發中使用最多的方法,但是Collection接口很少在開發中直接使用,往往都會使用它的子接口:List(允許有重復元素,Set(不允許有重復元素)。



Collection接口的具體實現類
一些類提供了完整的可以被使用的工具。另一些類是抽象的,提供主框架工具,作為創建具體類集的起始點。沒有一個屋Collection接口是同步的,但是可以通過一些方法獲得同步版本。標準的Collection實現類如下:

描述
AbstractCollection 實現大多數Collection接口
AbstractList 擴展AbstractCollection并實現大多數List接口
AbstractSequentialList 為了被類集使用而擴展AbstractList,是連續而不是用隨機方式訪問其元素
LinkedList 通過擴展AbstractSequentialList來實現鏈接表
ArrayList 通過擴展AbstractList來實現動態數組
AbstractSet 擴展AbstractCollection并實現大多數Set接口
HashSet 為了使用散列表而擴展AbstractSet
TreeSet 實現存儲在數中的一個集合,擴展AbstractSet

除了Collection接口之外,還有幾個以前版本遺留下來的類,如Vector,Stack和Hashtable等均被重新設計成支持類集的形式。



允許重復的子接口---List
List(列表)是Collection接口之中最為常見的一個子接口。 List子接口定義:
public interface List<E> extends Collection<E>
List子接口對Collection接口進行了大量的擴充。List接口擴展了Collection并聲明存儲一系列元素的類集的特性。使用一個基于零的下標,元素可以通過他們在列表中的位置被插入和訪問。
一個列表可以包含重復的元素,即可以存在完全相同的兩個元素。除了由Collection定義的方法之外,List還定義了一些他自己的方法。注意:當類集不能被修改時,其中幾種方法將引發UnsupportedOperationException異常。當一個對象與另一個不兼容時,例如企圖將一個不兼容的對象加入一個類集中,將產生ClassCastException異常

方法 描述
void add(int index,Object obj) 將obj插入調用列表,插入位置的下標由index傳遞。任何已存在的,在插入點以及插入點之后的元素將后移。因此沒有元素被覆寫
boolean addALL(int index,Collection c) 將c中的所有元素插入到調用列表中,插入點的下標由index傳遞。在插入點以及插入點之后的元素將后移。因此,沒有元素被覆寫。如果調用列表變了,則返回true,否則返回false
Object get(int index) 返回存儲在調用類集指定下標處對象
int indexOf(Object obj) 返回調用列表中obj第一次出現的下標。如果obj不是列表中的元素,則返回-1
int lastIndexOf(Object obj) 返回調用列表中obj最后一次出現的下標。如果obj不是列表中的元素則返回-1
ListIterator listIterator() 返回調用列表開始的迭代器
ListIterator listIterator(int index) 返回調用列表在指定下標處開始的迭代器
Object remove(int index) 刪除調用列表中index位置的元素并返回刪除的元素刪除后,列表被壓縮。也就是說被刪除元素的后面的元素下標減一
Object set(int index,Object obj) 用obj對調用列表內由index指定的位置進行賦值
List subList(int start,int end) 返回一個列表,該列表包括了調用列表中從start到end-1的元素。返回列表中的元素也被調用對象引用

對于由Collection定義的add()和addALL()方法,List增加了方法add(int,Object)和addALL(int,Collection)的語義也被List改變了,以便他們在列表的尾部增加元素。
為了獲得在指定位置存儲的對象,可以用對象的下標調用get()方法。為了給類集中的一個元素賦值,可以調用set()方法,指定被改變的對象的下標。調用indexOf()或lastIndexOf()可以得到一個對象的下標。通過調用subList()方法,可以獲得列表的一個指定了開始下標和結束下標的子列表。
由于List本身還屬于接口,要想使用接口,就必須知道實現這個接口的子類,在List接口中有兩個最為常用的子類:ArrayList,Vector



ArrayList類
ArrayList類擴展AbstractList并執行List接口。ArdayList支持可隨需要而增長的動態數組。在Java中,標準類型的數組是定長的。一旦數組被創建之后,他們不能被加長或縮短,這就意味著開發者必須事先知道數組可以容納多少元素。
但是一般情況下,只有在運行時才知道需要多大的數組。為了解決這個問題,類集框架定義了ArrayList。本質上,ArrayList是對象引用的一個變長數組。也就是說,ArrayList能夠動態的增加或減小其大小。數組列表以一個原始大小被創建。當超過了它的大小時,類集自動增大,當有對象被刪除,數組就可以縮小(動態數組也被從前版本遺留下來的類Vector所支持)。

ArrayList構造方法如下:
ArrayList()
ArrayList(Collection)
ArrayList(int capacity)
第一個構造方法構造一個初始容量為10的空列表。第二個構造方法建立一個數組列表,該數組列表由類c中的元素初始化。第三個構造方法建立一個數組列表,該數組有指定的初始容量(capacity),容量用于存儲元素的基本數組的大小。當元素被追加到數組列表上時,容量會自動增加。

ArrayList類使用范例
import java.util.*;
public class Main
{
    public static void main(String args[])
    {
        //創建一個ArrayList對象
        ArrayList<String> al=new ArrayList<String>();  //尖括號<>中的String表明ArrayList的數組鏈表對象al,這個數組鏈表中的元素為String類型。尖括號<>內的數據類型是可變的,除了String類型還可以是其他類型如Integer等,這表明變量類型也是可變的---這就是Java泛型的表現
        System.out.println("a1中元素的個數"+al.size());
        //向ArrayList對象中添加新內容
        al.add("C");   //在數組列表0位置添加元素C
        al.add("A");   //在數組列表1位置添加元素A
        al.add("E");   //在數組列表2位置添加元素E
        al.add("B");   //在數組列表3位置添加元素B
        al.add("D");   //在數組列表4位置添加元素D
        al.add("F");   //在數組列表5位置添加元素F
        al.add(1,"A2");  //把A2加在ArrayList對象的第二個位置
        System.out.println("a1加入元素之后的元素個數:"+al.size());
        System.out.println("a1的內容:"+al);   //顯示ArrayList數據
        al.remove("F");  //刪除元素F
        al.remove(2);  //刪除下標為2的元素
        System.out.println("a1刪除元素之后的元素個數:"+al.size());
        System.out.println("a1的內容:"+al);
        
    }
}

當對象被存儲在ArrayList對象中時,其容量會自動增加。然而也可以調用ensureCapacity()方法來人工增加ArrayList的容量。如果事先知道將在當前的類集中存儲大量數據時,可以這么做。在開始通過一次性人工增加它的容量,就能避免后面的再分配。因為在分配很花時間,避免不必要的處理可以提高性能。

ArrayList類使用范例
import java.util.*;
public class Main
{
    public static void main(String args[])
    {
        //創建一個ArrayList對象al
        ArrayList<Integer> al=new ArrayList<Integer>();
        //向ArrayList中加入對象
        al.add(new Integer(1));
        al.add(new Integer(2));
        al.add(new Integer(3));
        al.add(new Integer(4));
        System.out.println("ArrayList中的內容:"+al);
        //得到對象數組
        Object ia[]=al.toArray();
        int sum=0;
        //計算數組內容
        for(int i=0;i<ia.length;i++)
        {
            sum+=((Integer)ia[i].intValue();   //將元素轉換成Integer類型并取值
        }
        System.out.println("數組累加結果是:"+sum);
    }
}


LinkedList類
LinkedList類擴展了AbstractSequentialList類并實現List接口它提供了一個鏈接列表的數據結構。構造方法如下:
LinkedList()
LinkedList(Collection c)
第一個構造方法建立一個空的鏈接列表。第二個構造方法建立一個鏈接列表。該鏈接列表由類c中的元素初始化。
除了它繼承的方法之外,LikedList類本身還定義了一些有用的方法,這些方法主要用于操作和訪問列表。使用addFirst()方法可以在列表頭增加元素,使用addLast()方法可以在列表的尾部增加元素。形式如下:
void addFirst(Object obj)
void addLast(Object obj)
在這里obj是被增加的對象。
調用getFirst()方法可以獲得第一個元素,調用getLast()方法可以得到最后一個元素。形式如下:
Object getFirst();
Object getLast();
為了刪除第一個元素,可以使用removeFirst()方法。刪除最后一個元素,可以調用removeLast()方法。形式如下:
Object removeFirst();
Object removeLast();

LinkedList類的使用**
import java.util.*;
public class Main
{
    public static void main(String args[])
    {
        LinkedList<String> LL=new LinkedList<String>();
        //加入元素到LinkedList對象
        LL.add("F");
        LL.add("F");
        LL.add("D");
        LL.add("E");
        LL.add("C");
        //在鏈表的最后一個位置加上數據
        LL.addLast("Z");
        //在鏈表的第一個位置加上數據
        LL.addFirst("A");
        //在鏈表第二個元素的位置加上數據
        LL.add(1,"A2");
        System.out.println("LL最初的內容:"+LL);
        //從LinkedList中移除元素
        LL.remove("F");
        System.out.println("刪除元素Fh后LL的內容:+"+LL);
        LL.remove(2);
        System.out.println("從LL中移除第二個元素后的內容:"+LL);
        //移除第一個和最后一個元素
        LL.removeFirst();
        LL.removeLast();
        System.out.println("LL移除第一個和最后一個元素之后的內容:"+LL);
        //取得并設值
        Object val=LL.get(2);
        LL.set(2,(String)val+"Changed");
        System.out.println("LL被改變之后:"+LL);
    }
}


舊的子類---Vector
Vector實現動態數組,與ArrayList相似,但兩者不同的是:Vector是同步的,并且它包含了許多不屬于類集框架的從以前版本遺留下來的方法。隨著Java2的公布,Vector被重新設計來擴展AbstractList和實現List接口,因此他是與類集完全兼容的。下面構造方法:
Vector()
Vector(int size)
Vector(int size,int incr)
Vector(Collection c)
第一種形式創建一個原始大小為10的默認矢量。第二種形式創建一個其原始容量由size指定的矢量。第三種形式創建一個其原始容量由size指定,并且它的增量由incr指定的矢量,增量指定了矢量每次允許向上改變大小的元素個數。第四種形式創建一個包含類集c中元素的矢量。
所有矢量開始都有一個原始的容量。在這個原始容量達到以后,下次在試圖向矢量中存儲對象時,矢量會自動為那個對象分配空間,同時分別為對象增加額外的空間。通過分配超過需要的內存,減小了矢量可能產生的分配次數。這種次數的減少是很重要的,因為分配內存很花時間,在每一次再分配中,分配的額外空間的總數由在創建矢量時指定的增量來確定。如果沒有指定增量,在分配周期,矢量的大小增加一倍。
Vector定義了下面的保護數據成員:
int capacityIncrement;
int elementCount;
Object elementData[ ];
增量值被存儲在capacityIncrement中,矢量中的當前元素的個數被存儲在elementCount中,保存矢量的數組被存儲在elementData中。
除了由List定義類集方法之外,Vector還定義了幾個以前版本遺留下來的方法:

方法 描述
finalvoiddaddElement(Objectelement) 將element指定的對象加入矢量
intcapacity() 返回矢量的容量
Objectclone() 返回調用矢量的一個備份
booleancontains(Objectarray[]) 將包含在調用矢量中的元素復制到由array指定的數組中
ObjectelementAt(intindex) 返回由index指定位置的元素
Enumerationelements() 返回矢量中元素的一個枚舉
ObjectfirstElement() 返回矢量的第一個元素
intindexOf(Objectelement) 返回element首次出現的位置下標。如果對象不在矢量中,則放-1
intindexOf(Objectelement,intstart) 返回element在矢量中,在start以及之后第一次出現的位置下標。如果該對象不屬于矢量的這一部分,則返回-1
voidinsertElementAt)Objectelement,int index) 在矢量中,在由index指定的位置處加入element
booleanisEmpty() 如果矢量是空的,則返回true,如果他包含了一個或更多個元素,則返回false
ObjectlastElement() 返回矢量中最后一個元素
intlastIndexOf(Objectelement) 返回element在矢量中最后一次出現的位置下標。如果對象不包含在矢量中,則返回-1
intlastIndexOf(Objectelement,intstart) 返回element在矢量中,在start之前最后一次出現的位置下標。如果該對象不屬于矢量的這一部分,則返回-1
voidremoveALLElements() 清空矢量,在這個方法執行以后,矢量大小為0
booleanremoveElement(Objectelement) 從矢量中刪除element。對于指定的對象,矢量中如果有許多個實例,則其中的第一個實例被刪除。如果刪除成功,則返回true,如果沒有發現對象,則返回false
voidremoveElementAt(intindexx 刪除由index指定位置處的元素
voidsetElementAt(Objectelement,intindex) 將由index指定的位置分配給element
voidsetSize(intsize) 講矢量中元素個數設置為size。如果新的長度小于老的長度,元素將會丟失,如果新的長度大于老的長度,則在后增加null元素
intsize() 返回矢量中當前元素的個數
StringtoString() 返回矢量的字符成為等價形式
voidtrimToSize() 將矢量的容量設為與其當前擁有的元素個數相等

因為Vector實現List,所以可以像使用ArrayList的一個實例那樣使用矢量。也可以使用從它的以前版本遺留下來的方法來操作她。例如,在后面實例化Vector,可以通過調用addElement()方法而為其增加一個元素。調用element()可以獲得指定位置處的元素。
調用firstElement()方法可以得到矢量的第一個元素,調用lastElement()可以檢索到矢量的最后一個元素,使用indexOf()和lastIndexOf()方法可以獲得元素的下標,調用removeElement()或removeElementAt()方法可以刪除元素。

使用矢量存儲不同類型的數值對象
import java.util.*;
class jdjdkdxk
{
    public static void main(String args[])
    {
        Vector<String> v=new Vector<String>();
        v.add("A");
        v.add("B");
        v.add("C");
        v.add("D");
        v.add("E");
        v.add("F");
        Enumeration<String> e=v.elements();
        while(e.hasMoreElements())
        {
            System.out.println(e.nextElement()+"   ");
        }
    }
}
枚舉方法nextElement()用于獲得枚舉中的下一個元素

Java2以后,Vector增加了對迭代(Iterator)方法的支持。可以使用迭代方法來代替枚舉去遍歷對象。下例基于迭代方法的程序代碼可以被替換到上面的程序中

import java.util.*;
class jdjdkdxk
{
    public static void main(String args[])
    {
        Vector v=new Vector();
        v.add("A");
        v.add("B");
        v.add("C");
        Iterator i=v.iterator();
        while(i.hasNext())
        {
            System.out.println(i.next()+"\t");
        }
    }
}


數組操作類------Arrays
本質上,類集本身是一個對象數組。java.util.Arrays類是可以操作數組的。Arrays類數組操作類,可用來操作數組(如數組元素排序,搜索和填充等)的各種方法。Arrays類常用如下方法表示:

方法名稱 類型 功能簡述
static<T>List<T> asList(T...a) 靜態 將多個元素變為List集合
static int binarySearch(int[] a,int key) 靜態 使用二分搜索法,查詢key元素值是否在a數組中,若不存在則返回負數,調用次方法前要求數組以升序排序。次方法可以被多次重載
static int[] copyOf(int[] original,int newLenggh 靜態 復制指定的數組。original表示原數組,newLength表示需要復制的長度,默認從第一個元素開始賦值。次方發可以被多次重載。
static int[] copyOf(int[] original,int newLength) 靜態 newLength表示需要復制的長度。默認從第一個元素開始賦值。此方發可以被多次重載
static boolean equals(int[] a,int[] a2) 靜態 比較兩個數組是否相等,若相等則返回true,否則返回false。此方發可以被多次重載
static void fill(int[] a,int val) 靜態 將指定的int val分配給指定的int型數組的每個元素。此方發可以被多次重載
static void sort(int[] a) 靜態 對指定的數組按升序排序。此方發可以被多次重載
static String toString(int[] a) 靜態 返回指定數組內容的字符串表示形式。此方發可以被多次重載


使用數組操作類Arrays的使用(ArrayDemo.java)

import java.util.List;
public class ArrayDemo
{
public static void main(String args[])
{
List<String> all=Arrays.asList("Hello","World","你好","世界");
System.out.println(all);
}
}


數組操作類Arrays排序及二分查找方法的使用

import java.util.Arrays;
import java.util.Scanner;
class ArraysDemo
{
    public static void main(String args[])
    {
        int arrInt[]={17,40,12,6,15,16,8,10,18,50};
        //升序排序數組
        Arrays.sort(arrInt);
        Scanner scan =new Scanner(System.in);
        System.out.println("請輸入需要查找的整數:");
        //獲取輸入整數
        int search=scan.nextInt();
        //輸出排序后的數組
        for(int i=0;i<arrInt.length;i++)
        {
            //System.out.println(arrInt(i)+ " ");
        }
        //利用二分法查找指定整數
        int seaInt=Arrays.binarySearch(arrInt,search);
        if(seaInt>=0)
        {
            System.out.println(search+" 是數組得第 "+(seaInt+1)+" 位元素");
        }
        else
        {
            System.out.println(search +"不是數組得元素");
        }
        scan.close();   //關閉輸入流
    }
}


比較器

需要為多個對象排序時必須設置排序規則,而排序規則就可以通過比較器進行設置,Java中比較器提供了兩種:Comparable和Comparator

Comparable接口
Comparable是一個要進行多個對象比較的類需要默認實現的一個接口,這個接口定義如下:
public interface Comparable<T>
{public int comparableTo(T o)};//T是對象類型,o是對象類型所定義得對象
從接口定義的格式來看,可以發現要想實現對象得排序功能,要實現Comparable接口,并覆寫comparable(T o)方法。此方法返回得是一個int類型數據,該返回值只能有以下三種情況之一
1,相等:0;
2,大于:1;
3,小于:-1;

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,779評論 18 399
  • ArrayList可以說是在Java開發中最常用的集合容器了,今天就來分析一下ArrayList的源碼,可以更加深...
    xiaoyanger閱讀 498評論 1 3
  • 雖然面試的要求是要知道HashMap是怎么實現的,令人望而卻步,但搞明白它怎么用,就成功了一小半。本文基于Mars...
    Sia_Coding閱讀 880評論 1 7
  • 1.import static是Java 5增加的功能,就是將Import類中的靜態方法,可以作為本類的靜態方法來...
    XLsn0w閱讀 1,267評論 0 2
  • 基礎入門文檔建議直接查看React中文文檔,這樣能少走很多彎路,官方文檔地址:Vue Router 路由設置 ro...
    阿爾法乀閱讀 2,453評論 1 4