分類
Java的容器類分爲Collection和Map兩種類型
Collection:描述了一個集合的概念,根據不同的需求又提供了不同的實現。List 集合必須按照插入的順序保存對象;Set集合中不能有重複元素;Queue集合按照 隊列的規則進行元素操作。
Map:map中保存的是“鍵值對”對象,它允許使用者通過對象(鍵)來查找對象(值)。
Collection
- 添加元素
Collection<Integer> collection = new ArrayList<>(); //傳統創建方式
Collections.addAll(collection,1,2,3,4,5); //爲collection對象添加元素,理論上要快一點
collection.addAll(Arrays.asList(6,7,8,9,10)); //爲collection對象添加元素
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); //接受可變參數,然後返回一個AbstractList類型的對象
//list.add(6); //運行時會報錯,因爲AbstractList對底層數組沒有提供擴展機制
值得一提的是Arrays.asList()方法對所保存的對象的類型做出最理想的假設,即以你傳進去的參數的類型爲準,例如:
Arrays.asList(1,2,3,4,5); //那保存的對象類型就是Integer
List<Fruit> fruits = Arrays.asList(new Orange(), new Apple()); //這時會保存爲其父類的類型
//Arrays.<String>asList(1); //可以在asList方法前加<>指定容器的類型,此時在向容器中添加其他類型就會在編譯時報錯
//List<String> l = Arrays.asList(1, 2, 3, 4); //返回的容器類型爲Integer類型,卻把他保存在String類型容器聲明的變量中會在編譯時報錯
- List
List提供了保存所有數據對象的功能,提供了比Collection接口更多的操作。他的實現類包括ArraysList和LinkedList。兩者的不同之處在於ArraysList使用數組(順序表)作爲底層所以適合隨機存取。但是不利於刪除和插入操作(因爲極可能會涉及大量數據的移動);而LinkedList使用雙向鏈表作爲底層極大的方便了插入和刪除操作,但不方便隨機存取(必須從第一個元素開始挨個比較,直到找到要找的元素)。
LinkedList
除了底層的實現方式的差別外,LinkedList還比ArrayList提供了更多的方法,實現了棧、隊列、雙端隊列等的數據結構(當然棧和隊列其實Java有單獨的實現)。
下面我們就用LinkedList的方法來實現一個我們自定義的棧結構
class Stack<E> {
private LinkedList<E> storage = new LinkedList<>();
public void push(E e) {
storage.push(e);
}
public E top() {
return storage.getFirst();
}
public E pop() {
return storage.pop();
}
public boolean isEmpty() {
return storage.isEmpty();
}
}
對於棧推薦使用LinkedList來實現而避免使用Java提供的Stack。因爲Stack的底層是使用數組來實現的,在壓入元素或者彈出元素時會涉及到數組的擴張或者收縮。
2. Iterator
Iterator
Iterator僅能單向移動,只能使用四個方法:
a. iterator(),獲取一個Iterator對象,該對象將會準備好該列表中的第一個數據元素
b. hasNext() 判斷列表中是不是還有未取出的元素
c. next() 取出下一個元素
d. remove() 刪除上一次取出的元素(這意味着在我們使用remove方法之前必須先使用next方法)
ListIterator
ListIterator是一個專門針對List容器的一個迭代器,與Iterator的不同之處在於:a.
a. ListIterator支持雙向移動
b. 可以使用nextIndex()和previousIndex()方法獲取當前指針指向的元素的索引和上一元素的索引
c. 可以使用set()方法替換掉上一次取出的元素的值。
-
Set
Set集合的特點是不保存重複元素,所以我們經常使用Set來判斷元素的歸屬問題。HashSet、TreeSet和LinkedHashSet是Set的三個重要實現。
HashSet採用了散列的方式存儲存數據,所以存儲的數據是無序的方便快速查找。
TreeSet採用紅-黑樹結構來存儲數據,默認按照升序排序。
LinkedHashSet按照插入的順序保存數據的同時也保證了一定的查詢的效率。 -
Map
Map保存的對象是鍵值對,允許我們建立對象用於對象之間的映射,方便使用對象來查找對象。 -
Queue
LinkedList實現了Queue接口,所以LinkedList可以直接向上轉型使用Queue的方法。
PriorityQueue
PriortyQueue是一個優先級隊列,也就是說他建立隊列的方法是按照優先級規則來建立的,並不是誰先來誰就在第一個的位置。默認是按照自然序建立隊列,如果想按照其他順序則需要在構造方法中傳入Comparator(比較器)。 -
Foreach與迭代器
我們在使用數組和Collectioin對象的時候都用過foreach(增強for循環)來遍歷每一個元素。但是你知道爲什麼他們能夠被Foreach語句遍歷嗎?因爲他們實現了Iterable接口(數組沒有實現)。只要實現了Iterable接口那麼我們所創建的類的對象也可以使用Foreach語句來遍歷。例如:
package test;
import javax.swing.*;
import java.io.Serializable;
import java.util.*;
public class Test {
public static void main(String[] args) {
TestIterable t = new TestIterable();
for (String s : t) {
System.out.println(s);
}
}
static class TestIterable implements Iterable<String> {
private String[] s = "to be or not to be".split(" ");
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < s.length ? true : false;
}
@Override
public String next() {
return s[i ++];
}
};
}
}
}
這時我們已經可以使用Foreach語句來遍歷TestIterable類的對象了,可是如果我們現在除了要正序遍歷這個對象外還想逆序遍歷甚至亂序遍歷,這時該怎麼辦呢?毫無疑問繼承是完全可以的,我們可以再寫一個這個類的子類,然後重寫他的Iterator方法就行了。但是除此之外是不是還有更好的方法呢?我們發現foreach語句能夠便利的關鍵在於Iterable接口,所以只要滿足這個接口就行,這樣一來我們就可以寫一個方法來返回一個Iterable接口的實現就好了。這種已經有了一個接口但是還需要另外的接口的狀況就叫適配器模式。新的接口的實現就是適配器。
package test;
import javax.swing.*;
import java.io.Serializable;
import java.util.*;
public class Test {
public static void main(String[] args) {
TestIterable t = new TestIterable();
for (String s : t) {
System.out.println(s);
}
for(String s : t.reverse()) {
System.out.println(s);
}
for (String s : t.random()) {
System.out.println(s);
}
}
static class TestIterable implements Iterable<String> {
private String[] s = "to be or not to be".split(" ");
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < s.length ? true : false;
}
@Override
public String next() {
return s[i ++];
}
};
}
public Iterable<String> reverse() {
return new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return new Iterator<String>() {
private int i = s.length - 1;
@Override
public boolean hasNext() {
return i >= 0 ? true : false;
}
@Override
public String next() {
return s[i --];
}
};
}
};
}
public Iterable<String> random() {
return new Iterable<String>() {
@Override
public Iterator<String> iterator() {
List<String> list = new ArrayList<>(Arrays.asList(s));//將Arrays.asList(s)的結果又創建了一個新的ArrayList對象保存,如果直接在返回結果上進行洗牌則會導致s數組的順序也被打亂
Collections.shuffle(list,new Random(12));
return list.iterator();
}
};
}
}
}