這篇文章給大家聊聊關于arraylist擴容機制原理,以及為什么arraylist線程不安全對應的知識點,希望對各位有所幫助,不要忘了收藏本站哦。
Java ArrayList是基于數組實現的嗎有些數組可以存放基本類型,為什么List不可以
ArrayList相關的知識點也是java面試中最頻繁出現的點,下面從源碼的角度來分析下Arraylist!
1,ArrayList中的屬性:ArrayList中的屬性主要定義了一個對象數組(Object[]),大小(size),初始容量(DEFAULT_CAPACITY=10)等等,從屬性中就可以知道ArrayList的底層就是一個數組,使用泛型E來存放構造器中傳入的對象類型,當然ArrayList存放的并不是對象本身,而是對象的引用,所以ArrayList不能存放八個基本類型的數據;
2,ArrayList的主要方法:從下面截圖可以看出,ArrayList中的主要方法就是元素的add(增),remove(刪),set(改),get(查),而由這四大類方法自然衍生了獲取大小,擴容,清空,包含等方法!
下面就主要方法進行分析:
1,add方法(add(i),addAll()等類似):
①,先判斷加入元素后的數組大小,如果是小于初始容量則返回初始容量,否則返回+1后的容量值;②,容量加1,同時跟未加入元素時的數組length比較,如果大于length,則使用grow方法進行擴容;
③,intnewCapacity=oldCapacity+(oldCapacity>>1);>>右移符號,相當于除二,即新容量為老容量的(1+0.5=1.5)倍,再進行判斷是否新容量已經超限(Integer.MAX_VALUE-8),如果超限,則置為最大容量,否則使用Arrays.copyOf復制得到新數組;
2,remove方法(remove其他方法類似):
①,先判斷是否下標越界,越界拋出異常,否則繼續
②,獲取到相應下標的元素;
③,將下標后面的元素使用System.arraycopy往前移動一位;④,將遺留出的最后一位置為null,讓GC進行回收,并返回②中獲得的值;
3,get,set方法:比較簡單,就是使用指定下標進行數據替換或者獲取;
記錄幾個ArrayList中碰到的坑:
1,線程不安全:所有的數據存取都是線程不安全的,所以多線程環境要么使用Vector,要么使用CopyOnWriteArrayList;
2,Arraylist是實現了序列化接口的,但使用subList方法返回的是SubList對象,這個對象并沒有序列化,在網絡傳輸中會報錯的;
3,使用remove方法遇到的坑,因為remove方法重載了兩個,remove(inti)和remove(Objecto),如果是傳入Integer類型的參數,默認調用第二個,則刪除元素失敗,案例如下:
可以說ArrayList是JAVA開發過程中最常使用的數據結構,底層實現也不難,但是如果不了解的話,面試容易被問倒,更多的JAVA技術會一直持續分享的,敬請關注。。。謝謝!
list擴容怎么實現
ArrayList就是動態數組,用MSDN中的說法,就是Array的復雜版本,它提供了如下一些好處:動態的增加和減少元素實現了ICollection和IList接口靈活的設置數組的大小2、如何使用ArrayList最簡單的例子:ArrayListList=newArrayList();
arraylist和linkedlist的區別和使用場景
1、數據結構不同
ArrayList是Array(動態數組)的數據結構,LinkedList是Link(鏈表)雙向鏈表的數據結構。
2、空間靈活性
ArrayList其實最好需要指定初始容量的(當然有些程序員為了偷懶,根本不會去初始化,這其實對于代碼質量低的項目而言是無關緊要的)《1.其實在代碼規范里,都要手動設置,只是我們用默認而已,如果公司用一些代碼規范的工具來做代碼質量,會要求寫上的2.如果只是產品達到一定的量,初始容量還是有好處的》
LinkedList是比ArrayList靈活的,是根本不需要指定初始容量的
3、從線程安全性來講:ArrayList是線程不安全的,而LinkedList是線程安全的。
4、效率不同
當隨機訪問List(get和set操作)時,ArrayList比LinkedList的效率更高,因為LinkedList是線性的數據存儲方式,所以需要移動指針從前往后依次查找。ArrayList對于數據查詢非常快,但是插入與刪除元素比較慢;當對數據進行增加和刪除的操作(add和remove操作)時,LinkedList是恰好相反的,它的查詢速度非常慢,但是插入與刪除元素的速度非常快。
5、主要控件開銷不同
ArrayList主要控件開銷在于需要在lList列表預留一定空間;而LinkList主要控件開銷在于需要存儲節點信息以及節點指針。
copy on write有幾種常見實現方式
1、CopyOnWriteArrayList是線程安全的List,底層數據結構也是數組結構,不過通過volatile修飾,使得寫操作之后立即刷新內存,使得其他線程讀最新的數據。是基于CopyOnWrite機制實現的線程安全的List
2、CopyOnWriteArrayList每次插入數據都會進行一次擴容,容量加1,并且在寫之前都需要通過ReentrantLock加鎖處理,然后復制原數組,寫完數據之后直接覆蓋原數組
3、CopyOnWriteArrayList的讀操作沒有加鎖處理,所以會存在臟讀問題,可能會讀到其他線程以及修改,但是還沒有替換原數組的數據
4、CopyOnWriteArrayList每次插入數據都會涉及到數組的復制,所以不適合頻繁寫而導致頻繁復制數組的場景,而讀沒有加鎖,所以適合寫少讀多的場景。
5、CopyOnWriteArrayList通過迭代器循環時,只可以循環讀,而不可以執行寫操作,因為迭代的數據是副本數據。
6、CopyOnWriteArrayList的set方法當設置數據一直時也同樣會復制數組,不是為了保證數組的可見性,而是為了保證外部非volatile變量的happen-before關系,從而實現volatile的語義。
arraylist指定初始容量還會擴容嗎
ArrayList是經常會被用到的,一般情況下,使用的時候會像這樣進行聲明:
ListarrayList=newArrayList();
如果像上面這樣使用默認的構造方法,初始容量被設置為10。當ArrayList中的元素超過10個以后,會重新分配內存空間,使數組的大小增長到16。
可以通過調試看到動態增長的數量變化:10->16->25->38->58->88->…
比如:
ListarrayList=newArrayList(4);
將ArrayList的默認容量設置為4。當ArrayList中的元素超過4個以后,會重新分配內存空間,使數組的大小增長到7。
可以通過調試看到動態增長的數量變化:4->7->11->17->26->…
那么容量變化的規則是什么呢?請看下面的公式:
((舊容量*3)/2)+1
一旦容量發生變化,就要帶來額外的內存開銷,和時間上的開銷。
所以,在已經知道容量大小的情況下,推薦使用下面方式進行聲明:
ListarrayList=newArrayList(CAPACITY_SIZE);
Java:ArrayList、LinkedList、Stack怎么回答比較全面
List以及arrayList,linkedlist,stack的區別
首先List是接口,而后面四個是它的實現類
1.arrayList是一個數組,查詢效率快,但是插入刪除效率低,這是由于數組的特性決定的
2.linkedlist雙鏈表,查詢效率低,但是插入刪除效率高,這是由于鏈表的特性決定的
3.stack繼承vector,有著先進后出的特性
知道他們分別是什么了,區別也就很明了了,所以使用的時候需要根據不同場景去選擇
例如需要頻繁插入刪除的可以用linkedList,而需要頻繁查詢的可以用arrayList
而當你面對面試官總問你怎么倒敘輸出一段話的時候如:如何將helloworld!倒敘輸出成!worldhello的時候你可以選擇用stack
arraylist擴容機制原理和為什么arraylist線程不安全的問題分享結束啦,以上的文章解決了您的問題嗎?歡迎您下次再來哦!