目錄
Collection
1.出現版本
JDK1.2
2.解決問題
數組定長問題
3.定義
Collection接口是Java中保存單個對象的最頂層接口
public interface Collection<E> extends Iterable<E>
繼承了Interable接口
4.繼承關係
5.常用操作方法
-
添加元素:boolean add(E e);
-
刪除元素:boolean remove(Object o);
-
查找元素:boolean contains(Object o);
-
取得集合大小:int size();
-
轉爲數組:Object[] toArray();
-
取得類集的迭代器:Iterator<E> iterator();
-
Collection接口中兩個重要方法add()、inerator()在他的子接口中都有這兩個方法
1.List
1.1List接口
List子接口與Collection接口相比最大的特點在於其有一個get()方法,可以根據索引取得內容。由於List本身還是接口,要想取得接口的實例化對象,就必須有子類,在List接口下有三個常用子類:ArrayList、Vector、 LinkedList。
1.1.1獨有方法
index默認從0開始編號
-
根據索引下標取得元素:E get(int index);
-
根據索引下標修改元素,返回修改前的數據:E set(int index,E element);
1.1.2常用子類
1.2ArrayList
出現版本:JDK1.2
1.2.1基本操作
代碼:
package SaveSingle.RList;
import java.util.List;
import java.util.ArrayList;
public class test {
public static void main(String[] args){
// 此時集合裏面只保存String類型
List<String> list = new ArrayList<>();
list.add("Hello") ;
// 重複數據
list.add("Hello") ;
list.add("World") ;
System.out.println(list) ;
}
}
結果:
結論:List允許保存重複數據
1.2.2List的get()操作
代碼:
package SaveSingle.RList;
import java.util.List;
import java.util.ArrayList;
public class test {
public static void main(String[] args){
// 此時集合裏面只保存String類型
List<String> list = new ArrayList<>();
list.add("Hello") ;
// 重複數據 list.add("Hello") ;
list.add("World") ;
for(int i = 0;i < list.size();i++){
System.out.print(list.get(i)+"、");
}
}
}
結果:
結論:list可以通過get(索引)獲得數據元素
1.2.3Collection進行輸出處理
get()方法是List子接口提供的。如果現在操作的是Collection接口,那麼對於此時的數據取出只能夠將集合變爲對象數組操作
代碼:
package SaveSingle.RList;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
public class test {
public static void main(String[] args){
// 此時集合裏面只保存String類型
List<String> list = new ArrayList<>();
list.add("Hello") ;
// 重複數據
list.add("Hello");
list.add("World") ;
Object[] result = list.toArray();
System.out.println(Arrays.toString(result));
}
}
結果:
1.2.4添加自定義類
List集合中添加自定義類
使用contains()、remove()需要equals()的支持
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(!(obj instanceof Person)){
return false;
}
Person per = (Person) obj;
return this.age.equals(per.age)&&this.name.equals(per.name);
}
1.2.5底層數組擴容詳解
源代碼:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
minCapacity:所需的最小數組容量
oldCapacity:原先的數組容量(擴容前)
newCapacity:新的數組容量(擴容後)
MAX_ARRAY_SIZE:MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
分析:
-
獲取到原先的數組容量;
-
新容量= 1.5舊容量;
-
如果new < min(新容量 < 當前所需的最小容量),則將當前所需容量賦爲新的數組容量;
-
如果new > max(新容量 > 數組最大容量),調用hugeCapacity()函數
-
min < 0(當前所需最小容量 < 0),拋出內存錯誤異常;
-
min > max(當前所需最小容量 > 數組最大容量),此時將Integer.MAX_VALUE賦爲新的數組容量;否則,將MAX_ARRAY_SIZE賦爲新的數組容量;
-
1.3LinkedList
1.3.1出現版本
JDK1.2
1.3.2基本操作
和ArrayList操作差不多
1.4Vector
1.4.1提出版本
JDK1.0
1.4.2基本操作
代碼:
package SaveSingle.RList;
import java.util.List;
import java.util.Vector;
public class test {
public static void main(String[] args){
List<String> list = new Vector<>() ;
list.add("hello");
list.add("hello");
list.add("bit");
System.out.println(list);
list.remove("hello");
System.out.println(list);
}
}
結果:
1.4.3底層數組擴容詳解
源代碼:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
分析:
注意到,這裏與ArrayList那個擴容操作基本一致,但是有一句不同哦
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
簡單來講,一下這個語句吧,其他請看上面ArrayList那塊的部分
-
capacityIncrement是什麼?
protected int capacityIncrement;
這是什麼鬼,繼續找會發現,這個參數可以在實例化對象時自定義
public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; }
摸索許久,這個參數作用大概是:控制數組填滿了之後要怎麼增加,算是一種增加策略吧。
-
比如,在實例化對象時,給定capacityIncrement=10(>0),那麼後續newCapacity = oldCapacity+10;如果不給定值或者給一個<0的值,那麼後續newCapacity = 2oldCapacity;
1.5List子類的"炫耀"(各自優勢)
1.5.1ArrayList VS LinkedList
相同點:
-
出現版本:均出現與JDK1.2時期;
-
線程安全性:異步處理,線程不安全,效率較高
不同點:
-
ArrayList:基於數組實現,在實例化對象時自定義了數組大小,在內部就會開闢一個自定義大小的數組,存儲元素多導致數組容量不夠時,會進行動態擴容擴充數組的容量。但是,這種擴充並不是無限的(適用於經常查找的情況下)
-
LinkedList:底層採用雙向鏈表實現(不存在擴容操作);
特殊:是JDK Queue的一個子類(適用於增刪頻繁的情況下)
1.5.2ArrayList VS Vector
ArrayList | Vector | |
---|---|---|
出現版本 | JDK1.2 | JDK1.0 |
調用無參構造 | 懶加載策略,在構造方法階段並不初始化對象數組,第一次添加元素時初始化對象數組大小爲10 | 產生對象時,內部數組初始化爲10的數組 |
擴容策略 | 新數組大小變爲原數組的1.5倍 | 新數組大小變爲原數組的2倍 |
線程安全 | 異步處理,線程不安全,效率較高 | 在方法上加鎖(synchronized同步方法),線程安全,效率較低(鎖的是當前Vector對象,當前對象的所有方法均上鎖,其他線程不可調用)(讀讀互斥) |
遍歷 | 不支持較老的迭代器Enumeration | 支持較老迭代器Enumeration |
特殊 | JDK內置的Stack繼承Vector |
-
調用無參構造
-
ArrayList:
無參構造賦給底層數組一個空數組;
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
-
Vector:
構造函數時指定底層數組初始化大小爲10;
public Vector() { this(10); }
-
-
擴容策略
-
ArrayList:
擴容1.5倍;
int newCapacity = oldCapacity + (oldCapacity >> 1);
-
Vector:
擴容2倍;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
-
-
線程安全
-
ArrayList:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
-
Vector:
方法上加鎖;
public synchronized void addElement(E obj) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = obj; }
-
-
遍歷
Vector支持較老迭代器Enumeration,該方法返回一個Enumeration迭代器對象
public Enumeration<E> elements() { return new Enumeration<E>() { int count = 0; public boolean hasMoreElements() { return count < elementCount; } public E nextElement() { synchronized (Vector.this) { if (count < elementCount) { return elementData(count++); } } throw new NoSuchElementException("Vector Enumeration"); } }; }
-
特殊
Stack繼承了Vector,Stack類也是JDK1.0出現的
class Stack<E> extends Vector<E> {