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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构特性解析 (二) ArrayList

發布時間:2025/3/21 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构特性解析 (二) ArrayList 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

ArrayList可能是Java中使用次數最多的數據結構了,因此了解其特性比較重要

描述

ArrayList是一個數組隊列,相當于動態數組.與Java中的數組相比,它的容量能動態增長.

并且ArrayList還有一些添加,遍歷和移除的操作

特點

1.ArrayList內部實現是利用Java的數組

這是內部存儲數據的Object數組

add方法的實現方式,根據源碼可以看到,先判斷了一下容量,然后在當前已存放數據的size的位置設置為傳過來的數據,并且size+1

public boolean add(E e) {ensureCapacityInternal(size + 1); // 檢查容量(擴充機制)下面再說elementData[size++] = e;return true;}

2.ArrayList的空參構造默認長度不是10,而是0

ArrayList一共有三個構造方法

//1設置初始化容量 public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}//2默認的無參構造 public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}//3傳入一個Collection對象public ArrayList(Collection<? extends E> c) {elementData = c.toArray();if ((size = elementData.length) != 0) {// c.toArray might (incorrectly) not return Object[] (see 6260652)if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData, size, Object[].class);} else {// replace with empty array.this.elementData = EMPTY_ELEMENTDATA;}}

首先第三個構造不多說了,是把別的集合轉換為ArrayList內部的數組,然后如果有長度在設置一下size,跟本條關系不大

然后第一個構造,是指定默認的數組長度,小于0拋異常,等于零則設置內部數組為靜態的length為0的空數組

重點是第二個構造,直接賦值成如下的數組,可以看到是一個空容量的數組

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

而在第一次add的時候會進行擴容,代碼如下所示

private static final int DEFAULT_CAPACITY = 10;//默認第一次擴容的容量private void ensureCapacityInternal(int minCapacity) {//這里會傳入size+1,也就是1if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//如果是默認的空數組minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);//檢查容量并擴容}

3.ArrayList的擴容方式,是先創建一個更大的數組,然后把舊數組內容拷貝過去,在把內部數組設置為新的大數組

我們看其add方法實現

public boolean add(E e) {ensureCapacityInternal(size + 1); // 檢查自身的可用容量elementData[size++] = e;return true;}

如果ensureCapacityInternal檢查到容量不夠,最終會調用如下代碼

private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;//記錄當前的長度int newCapacity = oldCapacity + (oldCapacity >> 1);// >> 符號(右位移),相當于除2,所以擴容是1+0.5=1.5倍if (newCapacity - minCapacity < 0)//如果擴容后,容量還小于指定容量,就直接設置為指定容量,比如使用空參構造new,size為0,乘1.5還是0,就會在第一次擴容的時候設置為10newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)//長度過長檢查,如果長度溢出了int的值,就會變成負數導致拋異常(但說實話,它這個判斷還是有可能會int溢出)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);//進行數組拷貝工作,容量為新擴容的大小}

所以,如果事先知道元素的大小或大概的大小,可以在構造中傳入,就能減少擴容次數,能有效節省時間和減少內存消耗

4.ArrayList的indexOf實現是遍歷

public int indexOf(Object o) {if (o == null) {for (int i = 0; i < size; i++)if (elementData[i]==null)return i;} else {for (int i = 0; i < size; i++)if (o.equals(elementData[i]))return i;}return -1;}public int lastIndexOf(Object o) {if (o == null) {for (int i = size-1; i >= 0; i--)if (elementData[i]==null)return i;} else {for (int i = size-1; i >= 0; i--)if (o.equals(elementData[i]))return i;}return -1;}

可以看到,indexOf是從前向后遍歷,而lastIndexOf是從后向前遍歷,所以如果你大概知道想查找的元素在前或者后,使用對應的方法,可以更節省時間

5.因為內部使用的是數組,所以其特性也和數組特性類似

ArrayList根據索引的方式去查找數據,會比較快,不用進行循環或多次尋址

而遍歷查詢則需要遍歷索引來循環從數組中取出

6.ArrayList是線程不安全的

內部沒有使用鎖或同步機制,如果想要使用線程安全的ArrayList(類似特性),可以使用Collections.synchronizedList

7.ArrayList不支持forEach時修改數據

forEach其實是java的語法糖,內部使用的是迭代器Iterator,通過hasNext()和next()方法,來遍歷數據

private class Itr implements Iterator<E> {ArrayList的內部類迭代器protected int limit = ArrayList.this.size;int cursor; // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;public boolean hasNext() {return cursor < limit;}@SuppressWarnings("unchecked")public E next() {if (modCount != expectedModCount)throw new ConcurrentModificationException();int i = cursor;if (i >= limit)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i];}}

而內部有一個modCount變量,標識的是自身修改的次數,會在擴容時,remove時和clear時進行+1操作,而在迭代器內next()方法取數據的時候,會判斷modCount變量,看看到底修沒修改過原數據,如果修改過就會拋異常(這是為了數據的準確性)

如果想要避免上述問題,可以使用CopyOnWriteArrayList(線程安全,支持forEach時修改數據)

8.ArrayList支持隨機讀取,并且隨機添加和刪除效率不高

因為ArrayList的實現基于數組,所以根據索引來獲取是很快的

而添加到的時候,只有在添加在尾部時效率較好(且不觸發擴容)

而隨機插入,則會引起插入索引后面的位置都會被復制并向后位移,所以效率不高

刪除也是,只有刪除尾部時效率較好

隨機刪除會引起刪除的索引后面的位置都會被復制并向前位移,所以效率也不高

下一篇:?數據結構特性解析 (三) 鏈表

總結

以上是生活随笔為你收集整理的数据结构特性解析 (二) ArrayList的全部內容,希望文章能夠幫你解決所遇到的問題。

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