成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

為什么阿里巴巴要求謹慎使用ArrayList中的subList方法

開發 開發工具
subList是List接口中定義的一個方法,該方法主要用于返回一個集合中的一段、可以理解為截取一個集合中的部分元素,他的返回值也是一個List。

[[268976]]

集合是Java開發日常開發中經常會使用到的。在之前的一些文章中,我們介紹過一些關于使用集合類應該注意的事項,如《為什么阿里巴巴禁止在 foreach 循環里進行元素的 remove/add 操作》、《為什么阿里巴巴建議集合初始化時,指定集合容量大小》等。

關于集合類,《阿里巴巴Java開發手冊》中其實還有另外一個規定:

 

本文就來分析一下為什么會有如此建議?其背后的原理是什么?

1.subList

subList是List接口中定義的一個方法,該方法主要用于返回一個集合中的一段、可以理解為截取一個集合中的部分元素,他的返回值也是一個List。

如以下代碼:

  1. public static void main(String[] args) { 
  2.     List<String> names = new ArrayList<String>() {{ 
  3.         add("Hollis"); 
  4.         add("hollischuang"); 
  5.         add("H"); 
  6.     }}; 
  7.  
  8.     List subList = names.subList(0, 1); 
  9.     System.out.println(subList); 

以上代碼輸出結果為:

  1. [Hollis] 

如果我們改動下代碼,將subList的返回值強轉成ArrayList試一下:

  1. public static void main(String[] args) { 
  2.     List<String> names = new ArrayList<String>() {{ 
  3.         add("Hollis"); 
  4.         add("hollischuang"); 
  5.         add("H"); 
  6.     }}; 
  7.  
  8.     ArrayList subList = names.subList(0, 1); 
  9.     System.out.println(subList); 

以上代碼將拋出異常:

  1. java.lang.ClassCastException:  
  2. java.util.ArrayList$SubList cannot be cast to java.util.ArrayList 

不只是強轉成ArrayList會報錯,強轉成LinkedList、Vector等List的實現類同樣也都會報錯。

那么,為什么會發生這樣的報錯呢?我們接下來深入分析一下。

2.底層原理

首先,我們看下subList方法給我們返回的List到底是個什么東西,這一點在JDK源碼中注釋是這樣說的:

Returns a view of the portion of this list between the specifiedfromIndex, inclusive, and toIndex, exclusive.

也就是說subList 返回是一個視圖,那么什么叫做視圖呢?

我們看下subList的源碼:

  1. public List<E> subList(int fromIndex, int toIndex) { 
  2.     subListRangeCheck(fromIndex, toIndex, size); 
  3.     return new SubList(this, 0, fromIndex, toIndex); 

這個方法返回了一個SubList,這個類是ArrayList中的一個內部類。

SubList這個類中單獨定義了set、get、size、add、remove等方法。

當我們調用subList方法的時候,會通過調用SubList的構造函數創建一個SubList,那么看下這個構造函數做了哪些事情:

  1. SubList(AbstractList<E> parent, 
  2.             int offset, int fromIndex, int toIndex) { 
  3.     this.parent = parent; 
  4.     this.parentOffset = fromIndex; 
  5.     this.offset = offset + fromIndex; 
  6.     this.size = toIndex - fromIndex; 
  7.     this.modCount = ArrayList.this.modCount; 

可以看到,這個構造函數中把原來的List以及該List中的部分屬性直接賦值給自己的一些屬性了。

也就是說,SubList并沒有重新創建一個List,而是直接引用了原有的List(返回了父類的視圖),只是指定了一下他要使用的元素的范圍而已(從fromIndex(包含),到toIndex(不包含))。

所以,為什么不能講subList方法得到的集合直接轉換成ArrayList呢?因為SubList只是ArrayList的內部類,他們之間并沒有繼承關系,故無法直接進行強制類型轉換。

3.視圖有什么問題

前面通過查看源碼,我們知道,subList()方法并沒有重新創建一個ArrayList,而是返回了一個ArrayList的內部類——SubList。

這個SubList是ArrayList的一個視圖。

那么,這個視圖又會帶來什么問題呢?我們需要簡單寫幾段代碼看一下。

1、非結構性改變SubList

  1. public static void main(String[] args) { 
  2.     List<String> sourceList = new ArrayList<String>() {{ 
  3.         add("H"); 
  4.         add("O"); 
  5.         add("L"); 
  6.         add("L"); 
  7.         add("I"); 
  8.         add("S"); 
  9.     }}; 
  10.  
  11.     List subList = sourceList.subList(2, 5); 
  12.  
  13.     System.out.println("sourceList : " + sourceList); 
  14.     System.out.println("sourceList.subList(2, 5) 得到List :"); 
  15.     System.out.println("subList : " + subList); 
  16.  
  17.     subList.set(1, "666"); 
  18.  
  19.     System.out.println("subList.set(3,666) 得到List :"); 
  20.     System.out.println("subList : " + subList); 
  21.     System.out.println("sourceList : " + sourceList); 

得到結果:

  1. sourceList : [H, O, L, L, I, S] 
  2. sourceList.subList(2, 5) 得到List : 
  3. subList : [L, L, I] 
  4. subList.set(3,666) 得到List : 
  5. subList : [L, 666, I] 
  6. sourceList : [H, O, L, 666, I, S] 

當我們嘗試通過set方法,改變subList中某個元素的值得時候,我們發現,原來的那個List中對應元素的值也發生了改變。

同理,如果我們使用同樣的方法,對sourceList中的某個元素進行修改,那么subList中對應的值也會發生改變。讀者可以自行嘗試一下。

2、結構性改變SubList

  1. public static void main(String[] args) { 
  2.     List<String> sourceList = new ArrayList<String>() {{ 
  3.         add("H"); 
  4.         add("O"); 
  5.         add("L"); 
  6.         add("L"); 
  7.         add("I"); 
  8.         add("S"); 
  9.     }}; 
  10.  
  11.     List subList = sourceList.subList(2, 5); 
  12.  
  13.     System.out.println("sourceList : " + sourceList); 
  14.     System.out.println("sourceList.subList(2, 5) 得到List :"); 
  15.     System.out.println("subList : " + subList); 
  16.  
  17.     subList.add("666"); 
  18.  
  19.     System.out.println("subList.add(666) 得到List :"); 
  20.     System.out.println("subList : " + subList); 
  21.     System.out.println("sourceList : " + sourceList); 
  22.  

得到結果:

  1. sourceList : [H, O, L, L, I, S] 
  2. sourceList.subList(2, 5) 得到List : 
  3. subList : [L, L, I] 
  4. subList.add(666) 得到List : 
  5. subList : [L, L, I, 666] 
  6. sourceList : [H, O, L, L, I, 666, S] 

我們嘗試對subList的結構進行改變,即向其追加元素,那么得到的結果是sourceList的結構也同樣發生了改變。

3、結構性改變原List

  1. public static void main(String[] args) { 
  2.     List<String> sourceList = new ArrayList<String>() {{ 
  3.         add("H"); 
  4.         add("O"); 
  5.         add("L"); 
  6.         add("L"); 
  7.         add("I"); 
  8.         add("S"); 
  9.     }}; 
  10.  
  11.     List subList = sourceList.subList(2, 5); 
  12.  
  13.     System.out.println("sourceList : " + sourceList); 
  14.     System.out.println("sourceList.subList(2, 5) 得到List :"); 
  15.     System.out.println("subList : " + subList); 
  16.  
  17.     sourceList.add("666"); 
  18.  
  19.     System.out.println("sourceList.add(666) 得到List :"); 
  20.     System.out.println("sourceList : " + sourceList); 
  21.     System.out.println("subList : " + subList); 
  22.  

得到結果:

  1. Exception in thread "main" java.util.ConcurrentModificationException 
  2.     at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1239) 
  3.     at java.util.ArrayList$SubList.listIterator(ArrayList.java:1099) 
  4.     at java.util.AbstractList.listIterator(AbstractList.java:299) 
  5.     at java.util.ArrayList$SubList.iterator(ArrayList.java:1095) 
  6.     at java.util.AbstractCollection.toString(AbstractCollection.java:454) 
  7.     at java.lang.String.valueOf(String.java:2994) 
  8.     at java.lang.StringBuilder.append(StringBuilder.java:131) 
  9.     at com.hollis.SubListTest.main(SubListTest.java:28) 

我們嘗試對sourceList的結構進行改變,即向其追加元素,結果發現拋出了ConcurrentModificationException。

【本文是51CTO專欄作者Hollis的原創文章,作者微信公眾號Hollis(ID:hollischuang)】

 

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO
相關推薦

2019-09-04 11:02:54

繼承層次組合

2019-09-02 15:20:28

Java開發繼承

2018-12-29 15:41:41

阿里巴巴程序員serialVersi

2021-10-11 09:32:40

包裝類型屬性

2022-03-14 09:41:10

POJO類型系統

2018-10-16 15:34:17

阿里巴巴Apache Flin大數據

2020-09-22 11:40:53

BigDecimalequalsJava

2021-08-04 17:20:30

阿里巴巴AsyncJava

2013-08-22 09:26:38

去IOE王堅

2020-09-14 09:47:56

Java開發類型

2020-09-08 16:25:18

Apache BeancopyJava

2020-07-30 12:16:33

阿里巴巴Apache對象

2023-04-03 07:03:51

阿里巴巴List元素

2016-09-21 20:28:55

阿里巴巴IOE

2022-09-05 10:06:21

MySQL外循環內循環

2021-09-07 17:22:43

阿里巴巴辭職高薪

2025-04-17 08:47:23

2010-06-28 10:43:47

2022-08-22 08:07:45

DruidMySQL密碼

2021-10-20 14:53:31

Foreach強制阿里巴巴
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 免费在线观看一区二区 | 中文字幕亚洲一区二区三区 | 国产精品99久久久久久宅男 | 日本精品久久久久久久 | 欧美成人第一页 | 在线中文字幕亚洲 | 久久av资源网 | 少妇午夜一级艳片欧美精品 | 91精品国产综合久久福利软件 | 日韩av在线中文字幕 | 天堂成人国产精品一区 | 中文一区| 国产成人精品午夜视频免费 | 欧美日韩亚洲视频 | 国产伦精品一区二区三区高清 | 国产精品福利在线观看 | 91一区二区在线观看 | 日本午夜免费福利视频 | 一区二区三区四区电影 | 亚洲aⅴ| 欧美日韩在线免费观看 | 国产精品色哟哟网站 | 欧美一区二区三区电影 | 国产日韩精品视频 | 久久国产成人 | 又黄又爽的网站 | 九九在线视频 | 国产精品成人一区二区三区 | 中文字幕在线中文 | 福利视频1000 | av在线免费网站 | 亚洲精品乱码久久久久久蜜桃91 | 国精产品一品二品国精在线观看 | 国产在线观看一区二区 | 高清av在线 | 三级在线免费 | 久久精品中文字幕 | 免费日韩av | 欧美三区在线观看 | 精品国产一区二区三区久久久久久 | 色站综合 |