15.泛型數組列表【Java溫故系列】

參考自–《Java核心技術卷1》

1 泛型數組列表

在許多程序設計語言中,特別是C++,必須在編譯時就確定整個數組的大小。

在 Java 中,允許運行時確定數組的大小:

int size = ...;
Employee[] staff = new Employee[size];

當然,這並沒有完全解決運行時動態更改數組大小的問題。一旦確定了數組的大小,要想再改變它就不太容易了。在 Java 中,解決這個問題最簡單的方法就是使用 Java 中另外一個被稱爲 ArrayList 的類。它使用起來有點像數組,但在添加或刪除元素時,具有自動調節數組容量的功能

ArrayList 是一個採用類型參數的泛型類。爲了指定數組列表保存的元素對象類型,需要用一對尖括號將類名括起來加在後面,例如,ArrayList<Employee> .

聲明和構造一個保存 Employee 對象的數組列表:

ArrayList<Employee> staff = new ArrayList<Employee>();  //右邊的類型參數可以省略

這被稱爲“菱形”語法,因爲空尖括號<>就像是一個菱形。可以結合 new 操作符使用菱形語法。編譯器會檢查類型參數的泛型類型,然後將這個類型放在<>中。在上述例子中,new ArrayList<>() 將賦予一個類型爲 ArrayList<Employee>() 的變量,它的泛型類型爲 Employee.

:在 Java 的老版本中,使用 Vector 類實現動態數組。不過現在的 ArrayList 類更加有效。

使用 add 方法可以將元素添加到數組列表中:

staff.add(new Employee("name1",1000));   // Employee的構造方法(name,salary)
staff.add(new Employee("name2",1000));

數組列表管理着對象引用的一個內部數組。最終,數組的全部空間有可能全部被用盡:如果調用 add 且內部數組已經滿了,數組列表就將自動地創建一個更大的數組,並將所有的對象從原較小的數組中拷貝到新較大的數組中。

如果已經清楚或能夠估計出數組可能存儲的元素數量,就可以填充數組之前調用 ensureCapacity 方法:

staff.ensureCapacity(100);

此方法調用將分配一個包含100個對象的內部數組。此後調用100次 add ,而不用重新分配空間。

另外,還可以把初始容量傳遞給 ArrayList 構造器 new ArrayList<>(100);

:數組列表的容量(capacity)與數組的大小(size)有非常重要的區別:如果爲數組分配100個元素的存儲空間,數組就有100個空位置可以使用;而容量爲100個元素的數組列表只是擁有存儲100個元素的潛力(實際上,重新分配空間的話,將會超過100個),但是在最初,甚至完成初始化構造之後,數組列表根本就不含有任何元素。

size 方法將返回數組列表中包含的實際元素數目:

staff.size();

將返回 staff 數組列表的當前元素數量,等價於數組 a 的 a.length。

一旦能夠確定數組列表的大小不再發生變化,就可以調用 trimToSize 方法。這個方法將存儲區域的大小調整爲當前元素數量所需要的存儲空間數目。垃圾回收器將回收多餘的存儲空間。

一旦確定數組列表的大小,添加新元素就需要花時間再次移動存儲塊,所以應該在確定不會添加任何元素時,再調用 trimToSize 方法。


2 訪問數組列表元素

數組列表自動擴展容量的便利增加了訪問元素語法的複雜程度。其原因是:ArrayList 只是一個編寫且被放在標準庫的一個使用類,而不是 Java 程序設計語言的一部分。

使用 get 和 set 方法實現訪問或改變數組列表元素的操作

//設置第i個元素
staff.set(i,employee1);  //等價於對數組a的元素賦值 a[i]=employee1;

:只有 i 小於或等於數組列表的實際大小時,才能夠調用 list.set(i,x).(即只有經過 add 賦予真正存儲空間的數組列表元素才能使用 set 方法更改數組列表元素,它只能替換數組列表中已存在的元素內容)

//獲取下標爲i的元素
Employee e = staff.get(i);    //等價於取數組a的下標爲i的元素  e = a[i];

:沒有泛型類時,原始的 ArrayList 類提供的 get 方法只能返回 Object,因此,get 方法的調用者必須對返回值進行類型轉換。原始的 ArrayList 存在一定的危險性,它的 add 和 get 可以接受任意類型的對象:如

staff.set(i,"employee");  //將下表爲i的數組列表元素設爲字符串

編譯不會給出任何警告,只有在使用時進行類型轉換才能發現問題。如果使用現在的 ArrayList<Employee> 編譯器就能檢測到這個錯誤。

下面的這個技巧可以靈活地擴展數組,也可以方便地訪問數組元素:

1)創建數組,添加所有元素:

ArrayList<X> list = new ArrayList<>();
while(...){
	x =  ...;
	list.add(x);
}

2)使用 toArray 方法將數組元素拷貝到一個數組中:

X[] a = new X[list.size()];
list.toArray(a);

接下來就可以使用數組 a 訪問數組元素了。

除了在數組列表的尾部添加元素之外(不帶參數的 add),還可以在數組列表的中間插入元素:

int n = staff.size()/2;
staff.add(n,e);  //向數組列表下標爲n的位置插入元素e (帶索引的add方法)

爲了插入一個新元素,位於索引 n 之後的所有元素要後移一個位置。如果插入新元素後,數組列表的大小超過容量,則數組列表就會被重新分配空間。

同樣的,可以從數組列表中刪除一個元素:

Employee e = staff.remove(n);  //移除下標爲n的元素,並將該元素賦予e

位於下標 n 之後的所有元素都向前移動一個位置,並且數組的大小減1.

對數組列表實施插入和刪除元素的操作效率比較低。如果數組列表存儲的的元素較多,又經常需要從中間位置插入、刪除元素,就該考慮使用鏈表。

可以使用 for each 循環或 for 循環遍歷數組列表。

:以上 set,get,add,remove 的操作元素下標必須介於 0~size()-1 之間

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章