關於集合類,《阿里巴巴Java開發手冊》中其實還有另一個規定:java
本文就來分析一下爲何會有如此建議?其背後的原理是什麼?面試
subList是List接口中定義的一個方法,該方法主要用於返回一個集合中的一段、能夠理解爲截取一個集合中的部分元素,他的返回值也是一個List。數據庫
如如下代碼:數據結構
publicstaticvoidmain(String[]args){
List<String>names=newArrayList<String>(){{
add("填坑之路");
add("填坑之路chuang");
add("填");
}}; 併發
ListsubList=names.subList(0,1);
System.out.println(subList);
} 函數
以上代碼輸出結果爲:微服務
[填坑之路] 高併發
若是咱們改動下代碼,將subList的返回值強轉成ArrayList試一下:this
publicstaticvoidmain(String[]args){
List<String>names=newArrayList<String>(){{
add("填坑之路");
add("填坑之路chuang");
add("填");
}}; spa
ArrayListsubList=names.subList(0,1);
System.out.println(subList);
}
以上代碼將拋出異常:
java.lang.ClassCastException:java.util.ArrayList$SubListcannotbecasttojava.util.ArrayList
不僅是強轉成ArrayList會報錯,強轉成LinkedList、Vector等List的實現類一樣也都會報錯。
那麼,爲何會發生這樣的報錯呢?咱們接下來深刻分析一下。
首先,咱們看下subList方法給咱們返回的List究竟是個什麼東西,這一點在JDK源碼中註釋是這樣說的:
Returns a view of the portion of this list between the specifiedfromIndex, inclusive, and toIndex, exclusive.
也就是說subList 返回是一個視圖,那麼什麼叫作視圖呢?
咱們看下subList的源碼:
這個方法返回了一個SubList,這個類是ArrayList中的一個內部類。
SubList這個類中單獨定義了set、get、size、add、remove等方法。
當咱們調用subList方法的時候,會經過調用SubList的構造函數建立一個SubList,那麼看下這個構造函數作了哪些事情:
能夠看到,這個構造函數中把原來的List以及該List中的部分屬性直接賦值給本身的一些屬性了。
也就是說,SubList並無從新建立一個List,而是直接引用了原有的List(返回了父類的視圖),只是指定了一下他要使用的元素的範圍而已(從fromIndex(包含),到toIndex(不包含))。
因此,爲何不能講subList方法獲得的集合直接轉換成ArrayList呢?由於SubList只是ArrayList的內部類,他們之間並無繼承關係,故沒法直接進行強制類型轉換。
前面經過查看源碼,咱們知道,subList()方法並無從新建立一個ArrayList,而是返回了一個ArrayList的內部類——SubList。
這個SubList是ArrayList的一個視圖。
那麼,這個視圖又會帶來什麼問題呢?咱們須要簡單寫幾段代碼看一下。
一、非結構性改變SubList
獲得結果:
當咱們嘗試經過set方法,改變subList中某個元素的值得時候,咱們發現,原來的那個List中對應元素的值也發生了改變。
同理,若是咱們使用一樣的方法,對sourceList中的某個元素進行修改,那麼subList中對應的值也會發生改變。讀者能夠自行嘗試一下。
二、結構性改變SubList
獲得結果:
咱們嘗試對subList的結構進行改變,即向其追加元素,那麼獲得的結果是sourceList的結構也一樣發生了改變。
三、結構性改變原List
獲得結果:
咱們嘗試對sourceList的結構進行改變,即向其追加元素,結果發現拋出了ConcurrentModificationException。
以爲文章不錯就給小老弟點個關注吧,更多內容陸續奉上。
最後,分享一份面試寶典《Java核心知識點整理.pdf》,覆蓋了JVM、鎖、高併發、反射、Spring原理、微服務、Zookeeper、數據庫、數據結構等等。私信回覆「資料」獲取免費領取方式。
咱們簡單總結一下,List的subList方法並無建立一個新的List,而是使用了原List的視圖,這個視圖使用內部類SubList表示。
因此,咱們不能把subList方法返回的List強制轉換成ArrayList等類,由於他們之間沒有繼承關係。
另外,視圖和原List的修改還須要注意幾點,尤爲是他們之間的相互影響:
因此,阿里巴巴Java開發手冊中有另一條規定:
若是須要對subList做出修改,又不想動原list。那麼能夠建立subList的一個拷貝: