問:下面程序片段的輸出結(jié)果是什么?為什么?
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。
因為通過構(gòu)造方法創(chuàng)建的 list1 實質(zhì)上新的列表,其內(nèi)部實現(xiàn)是通過 copyof 動作生成的,生成的列表與原列表沒有任何關(guān)系(雖然是淺拷貝,但是由于元素是 String 類型,所以可以理解成是深拷貝),所以當(dāng)我們對 list 添加了元素后再與 list1 進(jìn)行對比會發(fā)現(xiàn)沒有任何關(guān)系,而依據(jù)集合的比較都是比較元素值,其實是因為 list2 添加了新元素,導(dǎo)致原來的列表 list 的元素改變了,所以 list 與 list1 自然不相等。對于 list2 來說 subList 產(chǎn)生的集合列表只是一個視圖,所有的修改操作都會作用于原集合列表上,所以修改 list2 就相當(dāng)于修改了 list 集合,可以去看 AbstractList 和 ArrayList 中 subList 的實現(xiàn),雖然生成了新的 ArrayList public 內(nèi)部類 SubList 實例,但是該實例中每個操作都傳遞操作了外部類 ArrayList 的對應(yīng)操作,所以返回 true。
問:如何優(yōu)雅的刪除列表區(qū)間,譬如有一個 List 里面有 100 個元素,現(xiàn)在想刪除 30 到 50 之間的元素,怎么寫代碼最優(yōu)雅?
答:常見的刪除操作都是通過遍歷刪除區(qū)間的,譬如 index 索引從 30 開始到 50 結(jié)束,總之都得兩三句代碼,而問題提到了優(yōu)雅就是說美觀簡潔咯,下面的方式即可:
list.subList(30, 50).clear();
所以說遇到類似場景還是使用這種優(yōu)雅方式吧,一行代碼簡潔大方。
問:下面程序片段運行結(jié)果是什么?為什么?
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ù)器與預(yù)期不相等了,所以拋出異常,切記通過 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),但是不是同一個子類,無法強(qiáng)轉(zhuǎn)為 ArrayList,修改方案為 subList 的返回接收聲明為 List<String> 類型即可。