數(shù)組是保存一組對(duì)象的最有效的方式,如果你想保存一組基本類型數(shù)據(jù),也推薦這樣方式,但是數(shù)據(jù)具有固定的尺寸,而在更一般的情況中,你在程序時(shí)并不知道將需要多少個(gè)對(duì)象,或者是否需要更復(fù)雜的方式來存儲(chǔ)對(duì)象,因此數(shù)組尺寸固定顯得過于受限了。
java實(shí)用類庫(kù)提供了一套想當(dāng)完整的容器類來解決這個(gè)問題,其中基本的類型是List,Set,Queue和Map。
下圖是簡(jiǎn)單的容器分類圖:(下圖來自《thinking in java》第十一章)

為了更加直觀的記憶,簡(jiǎn)化上圖:

java容器大致分為繼承Collection接口和繼承Map接口兩大類。繼承自Collection接口的容器,又分為Set,List接口:
1.Interface List
Type Parameters:
E - the type of elements in this list
是Collection的子接口,實(shí)現(xiàn)了List接口的容器類中的元素是有序的,且可以重復(fù)
List容器中的元素都對(duì)應(yīng)一個(gè)整數(shù)型的序號(hào)記載其在容器中的位置,可以根據(jù)序號(hào)存取容器中的元素
JDK提供的實(shí)現(xiàn)List接口的容器類有AbstractList, AbstractSequentialList, ArrayList, AttributeList, CopyOnWriteArrayList, LinkedList, RoleList, RoleUnresolvedList, Stack, Vector
2.Interface Set
Type Parameters:
E - the type of elements maintained by this set
是Collection的子接口,實(shí)現(xiàn)了Set接口的容器類的元素是無序的,但是不可以重復(fù),JDK提供的實(shí)現(xiàn)了Set接口容器類有AbstractSet, ConcurrentHashMap.KeySetView, ConcurrentSk
ipListSet, CopyOnWriteArraySet, EnumSet, HashSet, JobStateReasons, LinkedHashSet, TreeSet
Interface Map
Type Parameters: K - the type of keys maintained by this map V - the type of mapped values
實(shí)現(xiàn)Map接口的類用來存儲(chǔ)鍵-值對(duì)
Map接口的實(shí)現(xiàn)類有HashMap和TreeMap等
Map類中存儲(chǔ)的鍵-值對(duì)通過鍵來標(biāo)識(shí),所以鍵值不能重復(fù)
jdk提供實(shí)現(xiàn)Map容器類有:AbstractMap, Attributes, Auth
PRovider, ConcurrentHashMap, ConcurrentSkipListMap, EnumMap, HashMap, Hashtable,IdentityHashMap, LinkedHashMap, PrinterStateReasons, Properties, Provider, RenderingHints, SimpleBindings,TabularDataSupport, TreeMap, UIDefaults, WeakHashMap
具體可以參考官方API,有詳細(xì)的說明。http://docs.
Oracle.com/javase/8/docs/api/index.html
下面看一段代碼:
- public class Collection1 {
-
- private int i;
- private String name;
-
- public Collection1(int i,String name) {
- // TODO 自動(dòng)生成的構(gòu)造函數(shù)存根
- this.i = i;
- this.name = name;
- }
-
- public int geti(){
-
- return i;
- }
-
- public String getName(){
-
- return name;
- }
-
- public String toString(){
-
- return i + "-" +name +" ";
- }
- }
- public class Test {
-
- public static void main(String[] args){
-
- ArrayList<Collection1> c = new ArrayList<Collection1>();
- c.add(new Collection1(1, "diy"));
- c.add(new Collection1(2,"os"));
- c.add(new Collection1(3, "Lios"));
-
- for(int i=0;i<c.size();i++){
- System.out.print(c.get(i).geti() + " ");
- }
- /*
- for(Collection1 cc :c){
System.out.print(cc.geti() + " ");
}
*/ - }
- }
上面我們利用ArrayList容器類來盛放Collection1對(duì)象,如果要從容器中取出對(duì)象,只有上面的兩種方式么?當(dāng)然不是,還記得Object類中的toString()方法吧,通過重寫該方法,也可以打印出我們想要的結(jié)果。下面介紹另一種:
- public class Test {
-
- public static void main(String[] args){
-
- ArrayList<Collection1> c = new ArrayList<Collection1>();
- c.add(new Collection1(1, "diy"));
- c.add(new Collection1(2,"os"));
- c.add(new Collection1(3, "Lios"));
-
- Iterator<Collection1> ite = c.iterator(); //ArrayList類中實(shí)現(xiàn)iterator()方法,作用:Returns an iterator over the elements in this list in proper sequence.
-
- while(ite.hasNext()){
-
- Collection1 t = ite.next();
- System.out.print(t.geti() + " ");
- }
- }
- }
Iterator是什么?那么查下API先:
Interface Iterator
Type Parameters:
E - the type of elements returned by this iterator
原來它是接口,下面簡(jiǎn)單的介紹下:
Iterator對(duì)象稱作迭代器,用以方便的實(shí)現(xiàn)對(duì)容器內(nèi)元素的遍歷操作
Iterator接口定義了以下的方法:
default void : forEachRemaining(Consumer action)
Performs the given action for each remaining element until all elements have been processed or the action throws an exception.
boolean hasNext():判斷游標(biāo)右邊是否有元素
E next():返回游標(biāo)右邊的元素并將游標(biāo)移動(dòng)到下一個(gè)位置
default void remove():刪除游標(biāo)左面的元素在執(zhí)行完next之后該操作只能執(zhí)行一次
原來它是為了方便對(duì)容器內(nèi)元素更好地遍歷操作!關(guān)于更詳細(xì)的內(nèi)容,請(qǐng)讀者參考API.
如果想刪除容器中的元素怎么辦呢,查看api文檔發(fā)現(xiàn),提供我們r(jià)emove(Object o)方法,那就好辦啊!
- public class Test {
-
- public static void main(String[] args){
-
- ArrayList<Collection1> c = new ArrayList<Collection1>();
- c.add(new Collection1(1, "diy"));
- c.add(new Collection1(2,"os"));
- c.add(new Collection1(3, "Lios"));
-
- c.remove(new Collection1(1,"diy"));
- Iterator<Collection1> ite = c.iterator();
-
- while(ite.hasNext()){
-
- Collection1 t = ite.next();
- System.out.print(t.geti() + " ");
- }
- }
- }
咦?怎么打印結(jié)果沒有變化啊?不是刪除了么?c.remove(new Collection1(1,"diy"));我想有些朋友會(huì)這樣疑問,其實(shí)在調(diào)用remove()時(shí),系統(tǒng)會(huì)調(diào)用equals(Object o),如果容器中要?jiǎng)h除的對(duì)象this,和remove(Object o)函數(shù)的參數(shù)o相等的話,equals()返回true,否則返回false。對(duì)于自定義類型,那么需要重寫equals()方法和hashCode()方法,兩個(gè)equals的對(duì)象,那么它們的hashcode也是相等的。上述中remove(new Collection1(1,"diy")),傳入的Collection1的對(duì)象,和add(new Collection1(1,"diy"))中添加的對(duì)象,在堆中是兩片不同的內(nèi)存區(qū)域,所以是不同的對(duì)象,當(dāng)然不會(huì)刪除!那么沒有辦法刪除了么,當(dāng)然不是,我們可以通過對(duì)象引用的方式來刪除:
- public class Test {
-
- public static void main(String[] args){
-
- ArrayList<Collection1> c = new ArrayList<Collection1>();
-
- Collection1 diy = new Collection1(1, "diy");
- c.add(diy);
- c.add(new Collection1(2,"os"));
- c.add(new Collection1(3, "Lios"));
-
- c.remove(diy);
- Iterator<Collection1> ite = c.iterator();
-
- while(ite.hasNext()){
-
- Collection1 t = ite.next();
- System.out.print(t.geti() + " ");
- }
- }
- }
簡(jiǎn)單的修改Test.java:
- public class Test {
-
- public static void main(String[] args){
- HashSet<Collection1> c = new HashSet<Collection1>();
-
- Collection1 ss = new Collection1(1,"diy");
- c.add(ss);
- c.add(new Collection1(2, "os"));
- c.add(new Collection1(3, "Lios"));
- c.add(ss);
- Iterator<Collection1> ite = c.iterator();
-
- while(ite.hasNext()){
-
- Collection1 t = ite.next();
- System.out.print(t.geti() + " ");
-
-
- }
- }
- }
打印結(jié)果無序,而且不會(huì)出現(xiàn)重復(fù)對(duì)象,其中如何判斷放入的是不是同一對(duì)象也是用equals(Object o)來實(shí)現(xiàn)。
簡(jiǎn)單的修改Test.java:
- public class Test {
-
- public static void main(String[] args){
- HashMap<String, Integer> A = new HashMap<String, Integer>();
- A.put("One", 1);
- A.put("Two", 2);
- A.put("Three", 3);
- System.out.println(A.get("One"));
- }
- }
上述
put(K key, V value)中,第二個(gè)參數(shù)是Integer類型,但是直接寫int類型數(shù)字,無錯(cuò)誤,這是Java自動(dòng)打包解包緣由:
自動(dòng)將基礎(chǔ)類型轉(zhuǎn)換為對(duì)象
自動(dòng)將對(duì)象轉(zhuǎn)換為基礎(chǔ)類型
本文中沒有提及LinkedList類,和Interface Queue及其子類,因?yàn)楹罄m(xù)有文章提及Java中的算法數(shù)據(jù)結(jié)構(gòu),當(dāng)然java封裝了其中的算法,通過查閱API文檔,可以很好地掌握。
文中如有錯(cuò)誤之處,請(qǐng)讀者指正 !