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

歡迎訪問 生活随笔!

生活随笔

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

java

Java集合框架:ArrayList

發布時間:2024/4/11 java 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java集合框架:ArrayList 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。


歡迎跳轉到本文的原文鏈接:https://honeypps.com/java/java-collection-arraylist/

ArrayList定義

package java.util; public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable{private static final int DEFAULT_CAPACITY = 10;private static final Object[] EMPTY_ELEMENTDATA = {};private transient Object[] elementData;private int size; //其余省略 }

ArrayList概述

??ArrayList以數組實現,允許重復。超出限制時會增加50%的容量(grow()方法中實現,如下所示),每次擴容都底層采用System.arrayCopy()復制到新的數組,因此最好能給出數組大小的預估值。默認第一次插入元素時創建數組的大小為10.

private void grow(int minCapacity) {// overflow-conscious codeint 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);}

??按數組下標訪問元素—get(i)/set(i,e) 的性能很高,這是數組的基本優勢。

public E get(int index) {rangeCheck(index);return elementData(index);}public E set(int index, E element) {rangeCheck(index);E oldValue = elementData(index);elementData[index] = element;return oldValue;}

??直接在數組末尾加入元素—add(e)的性能也高,但如果按下標插入、刪除元素—add(i,e), remove(i), remove(e),則要用System.arraycopy()來移動部分受影響的元素,性能就變差了,這是基本劣勢。

public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true;}public void add(int index, E element) {rangeCheckForAdd(index);ensureCapacityInternal(size + 1); // Increments modCount!!System.arraycopy(elementData, index, elementData, index + 1,size - index);elementData[index] = element;size++;}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; // clear to let GC do its workreturn oldValue;}public boolean remove(Object o) {if (o == null) {for (int index = 0; index < size; index++)if (elementData[index] == null) {fastRemove(index);return true;}} else {for (int index = 0; index < size; index++)if (o.equals(elementData[index])) {fastRemove(index);return true;}}return false;}

?? ArrayList中有一個方法trimToSize()用來縮小elementData數組的大小,這樣可以節約內存:

public void trimToSize() {modCount++;if (size < elementData.length) {elementData = Arrays.copyOf(elementData, size);}}

??考慮這樣一種情形,當某個應用需要,一個ArrayList擴容到比如size=10000,之后經過一系列remove操作size=15,在后面的很長一段時間內這個ArrayList的size一直保持在<100以內,那么就造成了很大的空間浪費,這時候建議顯式調用一下trimToSize()這個方法,以優化一下內存空間。
??或者在一個ArrayList中的容量已經固定,但是由于之前每次擴容都擴充50%,所以有一定的空間浪費,可以調用trimToSize()消除這些空間上的浪費。
??非線程安全,可以調用Collections.synchronizedList(new ArrayList<>());實現。


ArrayList的使用

??舉個簡單一點的例子:

List<Integer> list = new ArrayList<>();list.add(4);list.add(2);list.add(3);list.add(5);for(int i:list){System.out.println(i);}System.out.println(list);

??運行結果:

4 2 3 5 [4, 2, 3, 5]

??可以發現ArrayList是按插入順序存儲的,這也不奇怪,每次插入是在elementData[size++]處插入。


subList的使用

List<Integer> list = new ArrayList<>();list.add(4);list.add(2);list.add(3);list.add(5);list.add(7);list.add(5);list.add(11);list.add(14);list.add(10);list.add(9);System.out.println(list);List<Integer> list2 = list.subList(3, 6);System.out.println(list2);list2.set(2, 50);System.out.println("============");System.out.println(list);System.out.println(list2);

??運行結果:

[4, 2, 3, 5, 7, 5, 11, 14, 10, 9] [5, 7, 5] ============ [4, 2, 3, 5, 7, 50, 11, 14, 10, 9] [5, 7, 50]

??調用ArrayList中的subList方法生成的新的list,內部引用的還是原來的數組elementData,如果改變subList中的值,主list中的值也會跟著改變。


RandomAccess?!

??但是,上面的程序有不合理之處!你們可能感到費解,請聽我一一道來。
??上面一段程序可以通過反編譯看到foreach語法糖經過編譯器處理成了Iterator的遍歷,有關foreach語法糖的細節可以參考《Java語法糖之foreach》。由于上面程序反編譯出來有100+行,太多了就不羅列了。只要知道一個事實就可以:foreach對于集合框架,編譯解析成的是Iterator的遍歷。
??那么這又有什么不妥?集合框架印象中不就是用迭代器遍歷的嚒?
??注意ArrayList的特殊之處在于它implements了RandomAccess這個接口,在JDK中RandomAccess明確說明:

It is recognized that the distinction between random and sequential access is often fuzzy. For example, some List implementations provide asymptotically linear access times if they get huge, but constant access times in practice. Such a List implementation should generally implement this interface. As a rule of thumb, a List implementation should implement this interface if, for typical instances of the class, this loop:for (int i=0, n=list.size(); i < n; i++)list.get(i);runs faster than this loop:for (Iterator i=list.iterator(); i.hasNext(); )i.next();

??這段英文主要說明的是實現了RandomAccess接口的集合框架,采用迭代器遍歷比較慢,不推薦。
??實現RandomAccess接口的集合有:ArrayList, AttributeList, CopyOnWriteArrayList, RoleList, RoleUnresolvedList, Stack, Vector等。
??所以上面的例子中的遍歷應該這么寫:

int length = list.size();for(int i=0;i<length;i++){System.out.println(list.get(i));}

??其實也可以加個判斷,讓程序通用起來:

if (list instanceof RandomAccess){for (int i = 0; i < list.size(); i++){}}else{Iterator<?> iterator = list.iterator();while (iterator.hasNext()){iterator.next();}}

??因此,博主個人覺得JDK(jdk7)中有這么一段不妥之處(希望大神不要噴我):ArrayList的toString()方法是在AbstractCollection中實現的:

public String toString() {Iterator<E> it = iterator();if (! it.hasNext())return "[]";StringBuilder sb = new StringBuilder();sb.append('[');for (;;) {E e = it.next();sb.append(e == this ? "(this Collection)" : e);if (! it.hasNext())return sb.append(']').toString();sb.append(',').append(' ');}}

??這里沒有判斷RandomAccess,直接采用的是迭代器的遍歷,影響了一些性能。


ArrayList和LinkedList的區別

  • ArrayList是實現了基于動態數組的數據結構,LinkedList基于鏈表的數據結構。
  • 對于隨機訪問get和set,ArrayList覺得優于LinkedList,因為LinkedList要移動指針。
  • 對于新增和刪除操作add和remove,LinkedList比較占優勢,因為ArrayList要移動數據。

  • ArrayList和Vector的區別

  • Vector和ArrayList幾乎是完全相同的,唯一的區別在于Vector是同步類(synchronized),屬于強同步類。因此開銷就比ArrayList要大,訪問要慢。正常情況下,大多數的Java程序員使用ArrayList而不是Vector,因為同步完全可以由程序員自己來控制。
  • Vector每次擴容請求其大小的2倍空間,而ArrayList是1.5倍。
  • Vector還有一個子類Stack.
  • 注意要點1

    示例代碼:

    List<Integer> arrayList = Arrays.asList(3, 2, 5, 4); arrayList.add(7);//錯誤,會報出異常:Exception in thread "main" java.lang.UnsupportedOperationException System.out.println(arrayList);

    原因

    Arrays.asList()方法的定義如下: public static <T> List<T> asList(T... a) {return new ArrayList<>(a); }

    這里的new ArrayList并非是java.util.ArrayList而是Arrays類中的私有靜態類:

    private static class ArrayList<E> extends AbstractList<E>implements RandomAccess, java.io.Serializable

    這個ArrayList中并未定義add(e)/remove(e)之類的方法,所以會報出UnsupportedOperationException。


    參考資料:

  • 《Java語法糖之foreach》
  • 歡迎跳轉到本文的原文鏈接:https://honeypps.com/java/java-collection-arraylist/


    歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。


    總結

    以上是生活随笔為你收集整理的Java集合框架:ArrayList的全部內容,希望文章能夠幫你解決所遇到的問題。

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