問:下面程序片段的輸出結果是什么玻褪?為什么?
List<String> list = new ArrayList<>();
list.add("android");
list.add("java");
List<String> list1 = new ArrayList<>(list);
List<String> list2 = list.subList(0, list.size());
list2.add("unix C");
System.out.println(list.equals(list1));
System.out.println(list.equals(list2));
答:輸出為 false公荧、true带射。
因為通過構造方法創(chuàng)建的 list1 實質上新的列表,其內(nèi)部實現(xiàn)是通過 copyof 動作生成的循狰,生成的列表與原列表沒有任何關系(雖然是淺拷貝窟社,但是由于元素是 String 類型,所以可以理解成是深拷貝)绪钥,所以當我們對 list 添加了元素后再與 list1 進行對比會發(fā)現(xiàn)沒有任何關系灿里,而依據(jù)集合的比較都是比較元素值,其實是因為 list2 添加了新元素程腹,導致原來的列表 list 的元素改變了匣吊,所以 list 與 list1 自然不相等。對于 list2 來說 subList 產(chǎn)生的集合列表只是一個視圖寸潦,所有的修改操作都會作用于原集合列表上色鸳,所以修改 list2 就相當于修改了 list 集合,可以去看 AbstractList 和 ArrayList 中 subList 的實現(xiàn)见转,雖然生成了新的 ArrayList public 內(nèi)部類 SubList 實例命雀,但是該實例中每個操作都傳遞操作了外部類 ArrayList 的對應操作,所以返回 true斩箫。
問:如何優(yōu)雅的刪除列表區(qū)間吏砂,譬如有一個 List 里面有 100 個元素,現(xiàn)在想刪除 30 到 50 之間的元素乘客,怎么寫代碼最優(yōu)雅狐血?
答:常見的刪除操作都是通過遍歷刪除區(qū)間的,譬如 index 索引從 30 開始到 50 結束易核,總之都得兩三句代碼氛雪,而問題提到了優(yōu)雅就是說美觀簡潔咯,下面的方式即可:
list.subList(30, 50).clear();
所以說遇到類似場景還是使用這種優(yōu)雅方式吧耸成,一行代碼簡潔大方。
問:下面程序片段運行結果是什么浴鸿?為什么井氢?
List<String> list = new ArrayList<>();
list.add("android");
list.add("java");
List<String> sublist = list.subList(0, list.size());
list.add("unix C");
System.out.println("list size=" + list.size());
System.out.println("sublist size=" + sublist.size());
答:這個程序運行會在 sublist.size() 處報錯 ConcurrentModificationException。因為 subList 取出的列表只是原列表的一個視圖岳链,原數(shù)據(jù)集合修改了后 subList 取出的子列表不會重新生成新的列表花竞,而 SubList 中每個方法都有修改計數(shù)檢測,后面再對子列表操作時就檢測到計數(shù)器與預期不相等了,所以拋出異常约急,切記通過 subList 生成子列表后不要再操作原列表零远。
問:下面程序有問題嗎?為什么厌蔽?
ArrayList<String> list = new ArrayList<>();
list.add("android");
ArrayList<String> subList = (ArrayList<String>) list.subList(0, 1);
subList.add("unix");
答:這個程序運行會拋出 java.lang.ClassCastException: java.util.ArrayList$SubList cannot be cast to java.util.ArrayList
異常牵辣。
因為 subList 返回的 List 是 ArrayList 內(nèi)部類 SubList(繼承自 AbstractList),看起來都是 List 的實現(xiàn)奴饮,但是不是同一個子類纬向,無法強轉為 ArrayList,修改方案為 subList 的返回接收聲明為 List<String> 類型即可戴卜。