日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java j集合_JNotes/Java-集合篇(2)集合之List.md at master · harryjudy2240/JNotes · GitHub...

發布時間:2024/4/20 java 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java j集合_JNotes/Java-集合篇(2)集合之List.md at master · harryjudy2240/JNotes · GitHub... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ArrayList

存儲機制

基于動態數組實現,默認長度 10 ;因為數組特性,其讀取速度快,增刪效率慢

因為寫入或讀取都是通過數組索引直接操作,所以,允許為 null 值, 且可以重復

當數組大小不滿足時需要增加存儲能力,就要將已經有數組的數據復制到新的存儲空間中。當從 ArrayList 的中間位置插入或者刪除元素時,需要對數組進行復制、移動、代價比較高。

因此,它適合隨機查找和遍歷,不適合插入和刪除。

類定義

在 jdk 8 中源碼如下

public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable{

private static final int DEFAULT_CAPACITY = 10; // 默認大小為 10

transient Object[] elementData; // 數組存儲

private int size;

}

ArrayList 實現了RandomAccess 接口, RandomAccess 是一個標志接口,表明實現這個這個接口的 List 集合是支持快速隨機訪問的。在 ArrayList 中,我們即可以通過元素的序號快速獲取元素對象,這就是快速隨機訪問。

ArrayList 實現了Cloneable 接口,即覆蓋了函數 clone(),能被克隆。

ArrayList 實現java.io.Serializable 接口,這意味著ArrayList支持序列化,能通過序列化去傳輸。

get()方法

public E get(int index) {

rangeCheck(index);

return elementData(index);

}

private void rangeCheck(int index) {

if (index >= size)

throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

}

通過以上代碼可以看出,ArrayList 通過索引讀取元素,所以其讀取元素效率高

add()方法

public boolean add(E e) {

ensureCapacityInternal(size + 1); // Increments modCount!!

elementData[size++] = e;

return true;

}

private void ensureCapacityInternal(int minCapacity) {

ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));

}

private static int calculateCapacity(Object[] elementData, int minCapacity) {

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

return Math.max(DEFAULT_CAPACITY, minCapacity);

}

return minCapacity;

}

private void ensureExplicitCapacity(int minCapacity) {

modCount++; // 迭代時,用來判斷是否被其他線程修改

if (minCapacity - elementData.length > 0)

// 擴容

grow(minCapacity);

}

private void grow(int minCapacity) {

int oldCapacity = elementData.length;

// 默認擴容 1.5 倍 ; >>1 相當于除 2

int newCapacity = oldCapacity + (oldCapacity >> 1);

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;

}

通過以上代碼發現,添加元素時會觸發擴容機制,當集合擴容時采用的是Arrays.copyOf(elementData, newCapacity),因此造成了新增元素速度慢

remove()方法

public E remove(int index) {

rangeCheck(index);

modCount++;

E oldValue = elementData(index);

int numMoved = size - index - 1;

if (numMoved > 0)

// 這行影響 速率

System.arraycopy(elementData, index+1, elementData, index, numMoved);

elementData[--size] = null;

return oldValue;

}

刪除方法同樣進行了數組復制,所以效率同樣不高

grow()方法

private void grow(int minCapacity) {

int oldCapacity = elementData.length;

// 默認擴容 1.5 倍 ; >>1 相當于除 2

int newCapacity = oldCapacity + (oldCapacity >> 1);

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;

}

1、默認初始容量 10,如果數據長度超過,則容量擴大為原來的 1.5倍,

2、然后會再判斷,擴容后的容量大小是否任然小于數據長度、是則,取為數據大小為最新容量大小

3、再判斷此時的最新容量大小是否超過最大容量值 MAX_ARRAY_SIZE,

4、是則,判斷數據大小是否超過最大容量值 ,

數據大小超過最大容量,則取 Integer 的最大值作為最新容量大小。

數據大小沒有最大容量,則取最大容量作為最新容量大小。

線程安全

ArrayList 線程不安全原因:使用數組存儲,當前多線程時,當對同一位置操作時,可能會被覆蓋,或者讀取到了未更新的數據等一系列問題。

線程安全解決方案

使用 Collections.synchronizedList(); 得到一個線程安全的 ArrayList。

使用 CopyOnWriteArrayList代替:讀寫分離的安全型并發集合對象,寫操作需要加鎖,防止并發寫入時導致寫入數據丟失。寫操作在一個復制的數組上進行,寫操作結束之后需要把原始數組指向新的復制數組。讀操作還是在原始數組中進行,讀寫分離,互不影響。

使用場景:適合讀多寫少的應用場景。

缺點 1 :內存占用:在寫操作時需要復制一個新的數組,使得內存占用為原來的兩倍左右;

缺點 2 :數據不一致:讀操作不能讀取實時性的數據,因為部分寫操作的數據還未同步到讀數組中。

List 和Array轉換

List 轉Array:使用 list.toArray()

Array 轉 List:使用 Arrays.asList(array)

//List 轉Array

List list = new ArrayList();

Object[] array=list.toArray();

//Array 轉 List

// 方式 1

List list = Arrays.asList(array); // 有缺陷

// 方式 2

List list = new ArrayList(Arrays.asList(array));

// 方式 3

List list = new ArrayList(array.length);

Collections.addAll(list, array);

注意:Arrays.asList(array) 不能作為一個 List 對象的復制操作

因為:方式 1 中 只是復制了引用,list 修改會改變 array 內容,因為返回的 list 是 Arrays 里面的一個靜態內部類,該類并未實現add、remove方法,因此在使用時存在局限性

所以,一般使用第 2 中和第 3 種方式轉換

String[] arr = {"1","2","3","4","5"};

List list1 = new ArrayList(Arrays.asList(arr));

List list2 = Arrays.asList(arr);

List list3 = new ArrayList(arr.length);

Collections.addAll(list3, arr);

list1.set(0, "a");

System.out.println("Array:"+Arrays.toString(arr));

System.out.println("List :"+list1.toString());

System.out.println();

list2.set(0, "b");

System.out.println("Array:"+Arrays.toString(arr));

System.out.println("List :"+list2.toString());

System.out.println();

list3.set(0, "c");

System.out.println("Array:"+Arrays.toString(arr));

System.out.println("List :"+list3.toString());

執行結果:

Array:[1, 2, 3, 4, 5]

List :[a, 2, 3, 4, 5]

Array:[b, 2, 3, 4, 5]

List :[b, 2, 3, 4, 5]

Array:[b, 2, 3, 4, 5]

List :[c, 2, 3, 4, 5]

ArrayList 去重

雙重for循環去重

通過set集合判斷去重,不打亂順序

遍歷后以 contains() 判斷賦給另一個list集合

set和list轉換去重

//雙重for循環去重

for (int i = 0; i < list.size() - 1; i++) {

for (int j = list.size() - 1; j > i; j--) {

if (list.get(j).equals(list.get(i))) {

list.remove(j);

}

}

}

//set集合判斷去重,不打亂順序

List listNew=new ArrayList<>();

Set set=new HashSet();

for (String str:list) {

if(set.add(str)){ //HashSet 內部維持map,其鍵唯一

listNew.add(str);

}

}

ArrayList 排序

可以使用如下方式

對象實現 Comparable 接口,

使用 Collections.sort(List list, Comparator super T> c),

使用 ArrayList#sort(Comparator super E> c)

前一種:重寫 compareTo(T o) 方法 ,后兩種:通過匿名內部類的方式實現比較器 Comparator 接口,重寫compare(T o1, T o2)

public class Student implements Comparable {

private int age;

@Override

public int compareTo(Student o) {

return this.age - o.age; // 升序

}

}

//自定義排序1

Collections.sort(list, new Comparator() {

@Override

public int compare(Student s1, Student s2) {

return s1.getAge() - s2.getAge();

}

});

//自定義排序2

new ArrayList().sort(new Comparator() {

@Override

public int compare(Student s1, Student s2) {

return s1.getAge() - s2.getAge();

}

});

Vector

同樣基于動態數組實現,但它是線程安全的,它支持線程的同步,但實現同步需要很高的花費,

因此,訪問它比訪問 ArrayList 慢。

LinkedList

基于雙向鏈表實現,只能順序訪問

因此,很適合數據的動態插入和刪除,隨機訪問和遍歷速度比較慢。

另外,他還提供了 List 接口中沒有定義的方法,專門用于操作表頭和表尾元素,可以當作堆棧、隊列和雙向隊列使用。

List 之間的區別

ArrayList 和 Vector 的

Vector 基本與ArrayList類似,數組存儲,排列有序,可重復,允許多個NULL1、

訪問效率比ArrayList稍慢,因為**Vector是同步的,線程安全**,它有對外方法都由 synchronized 修飾。

為什么要用Arraylist取代Vector呢

Vector類的所有方法都是同步的。可以由兩個線程安全地訪問一個Vector對象、但是一個線程訪問Vector的話代碼要在同步操作上耗費大量的時間。

Arraylist不是同步的,所以在不需要保證線程安全時時建議使用Arraylist。

Arraylist 與 LinkedList 區別

線程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保證線程安全;

底層數據結構:Arraylist 底層使用的是數組;LinkedList 底層使用的是雙向鏈表數據結構

插入和刪除是否受元素位置的影響

ArrayList 采用數組存儲,所以插入和刪除元素的時間復雜度受元素位置的影響,時間復雜度就為 O(n-i)

LinkedList 采用鏈表存儲,所以插入和刪除元素時間復雜度不受元素位置的影響,都是近似 O(1)而數組為近似 O(n)

是否支持快速隨機訪問: LinkedList 不支持高效的隨機元素訪問,而 ArrayList 支持。快速隨機訪問就是通過元素的序號快速獲取元素對象(對應于get(int index)方法)。

總結

以上是生活随笔為你收集整理的java j集合_JNotes/Java-集合篇(2)集合之List.md at master · harryjudy2240/JNotes · GitHub...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。