數組
-
數組創建與初始化
格式:className[] cn = new className[]{};
可以省略{},但必須在[]里表明長度(變量必須提供維度表達式或數組初始值設定項),可以不用new,直接使用{}初始化,數組在創建時指定長度后只能一個一個的填充數組,不能使用{ }填充數組優點:訪問效率高
缺點:數組長度固定
-
數組在方法內可以不初始化(自動初始化,例:int-->0)
-
在創建數組時其類型與數組長度固定(編譯時檢查,這是與其他容器類的不同之處)
-
可以使用length查看數組的長度(這是數組唯一可以調用的)
-
數組可以持有基本類型,容器的泛型不可以,但是有自動包裝機制
-
數組引用指向堆中真實對象,對象中保存其他對象的引用
-
-
可變參數列表
編譯器會把可變參數列表當做數組,所以可以進行foreach,可以對可以參數列表傳入數組
-
Arrays
sort(T[] t); //必須是基本類型或者實現Comparable接口的類型,否則出現異常,基本類型使用快排,引用類型使用穩定歸並 asList(T... a); //接收的可變參數,返回的是List接口類型的數據,不能強轉為List的其他實現類 fill(); //用指定數據填充整個數組 binarySearch(); //對已排序的數組查找,使用二分查找 copyof(); //拷貝數組,底層使用的是 System.arraycopy(): 淺復制: 復制對象的引用, 比for循環快很多, 因為for循環是對對象本身的拷貝(用於ArrayList數組的擴容), System.arraycopy()方法是native方法, 無法看到源碼(應該是C/C++實現的)
集合
-
創建集合時不跟泛型
編譯器檢查不出元素的類型,取元素時需要強轉,若強轉類型不對則報異常
-
使用Arrays.asList()生成的List
進行add()或delet()操作運行時會出異常,因為Arrays.asList()的底層為數組,長度不可改變
-
分類
-
Collection
-
List
ArrayList LinkedList
-
set
-
queue
-
-
map
-
List
-
特點
- 允許元素重復
- 記錄元素的位置
-
區別
ArrayList: 底層數據機構為數組, 隨機訪問較快, 增刪操作較慢
LinkedList: 底層數據結構為鏈表,增刪較快,隨機訪問較慢
ArrayList
-
隨機訪問元素較快, 不擅長操作插入刪除
-
add(int index, E element) 將指定的元素插入此列表中的指定位置。
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
初始化容量: 創建ArrayList時構造器初始化一個空數組, 當使用add()時, 把數組容量變為靜態字段 DEFAULT_CAPACITY=10
private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
1.5倍擴容 : 使用System.arraycopy進行擴容,每次擴容oldCapacity >> 1,位運算右移變為oldCapacity的一半,所以擴容為原來的1.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); }
-
remove() 移除指定數據數-----底層使用System.arraycopy進行數據挪移
-
線程不安全:
List list = Collections.synchronizedList(new ArrayList(...));//進行同步 -
容量大小和元素個數的關系??-----ArrayList里面有個int size表明當前的元素個數, 每次add元素就會進行size++, 當元素個數等於容量時就會擴容
-
default關鍵字(虛擬擴展方法), 可以在接口里對方法實現, List接口實現了sort()方法
迭代器
Iterator
- boolean hasNext() 如果仍有元素可以迭代,則返回 true
- E next() 返回迭代的下一個元素
- void remove() 從迭代器指向的 collection 中移除迭代器返回的最后一個元素(可選操作)
- default void forEachRemaining(Consumer<? super E> action)
ArrayList迭代器如下
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
-
不允許在foreach里刪除或添加(來自<<阿里巴巴Java開發手冊>>)
List<String> a = new ArrayList<>(); a.add("1"); a.add("2"); for (String string : a) { if("2".equals(string)) { a.remove(string); } System.out.printlb(String); }
異常: java.util.ConcurrentModificationException
**分析:**
1. remove("1")
第一輪: cussor=0,size=2,取出"1"后cussor+1,刪除"1"后size=1
第二輪: cussor=1,size=1, 經hasNext()判斷結束循環,元素"2"沒有得到遍歷
2. remove("2")
第一輪: cussor=0,size=2,取出"1"后cussor+1,size不變
第二輪: cussor=1,size=2, 取出"2"后cussor+1,刪除"2"后size=1
第三輪: cussor=2,size=1,hasNext()為true不能結束循環,此時進入next()方法內的checkForComodification()方法就拋出異常
**解決:**
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (item.equals"2") {
iterator.remove();
}
}
LinkedList
-
LinkedList中的鏈表節點:
private static class Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
-
方法:
普通增刪查: LinkedList的相比於ArrayList一般多First和Last方法
棧: 后進先出
push(): 往棧底(列表最后)壓入數據 pop(); 取出棧頂數據(列表開始) peek() 獲取列表第一個元素,peekFirst peekLast poll() 獲取第一個元素並移除改元素 pollFIrst pollLast