下邊是一個判斷列表相等的例子,代碼以下:java
1 public static void main(String[] args){ 2 ArrayList<String> arr1 = new ArrayList<>(); 3 arr1.add("A"); 4 5 Vector<String> arr2 = new Vector<>(); 6 arr2.add("A"); 7 8 System.out.print("" + arr1.equals(arr2)); 9 }
運行結果爲:true編程
緣由分析:兩者都是列表(List),實現了List接口,也都繼承了AbstractList抽象類,其equals方法是在AbstractList中定義的,其源代碼以下:數組
1 public boolean equals(Object o) { 2 if (o == this) 3 return true; 4 if (!(o instanceof List)) 5 return false; 6 7 ListIterator<E> e1 = listIterator(); 8 ListIterator<?> e2 = ((List<?>) o).listIterator(); 9 while (e1.hasNext() && e2.hasNext()) { 10 E o1 = e1.next(); 11 Object o2 = e2.next(); 12 if (!(o1==null ? o2==null : o1.equals(o2))) 13 return false; 14 } 15 return !(e1.hasNext() || e2.hasNext()); 16 }
能夠看到,這裏只要求實現List接口。只要List中全部的元素且位置相同,就代表兩個List是相等的。安全
其餘的集合類型,如Set、Map等與此相同,也是隻關心集合元素。併發
List提供了subList方法,用於返回一個列表的子列表。dom
1 public static void main(String[] args){ 2 List<String> c = new ArrayList<>(); 3 c.add("A"); 4 c.add("B"); 5 6 List<String> c1 = new ArrayList<>(c); 7 List<String> c2 = c.subList(0, c.size()); 8 c2.add("C"); 9 10 System.out.println("c == c1?" + c.equals(c1)); 11 System.out.println("c == c2?" + c.equals(c2)); 12 }
在上邊的例子中,c1是經過ArrayList的構造函數建立的,c2是經過subList方法建立的而後添加了一個元素。運行結果以下:函數
1 c == c1?false 2 c == c2?true
爲何會有上邊的結果呢?來看下subList的源碼:this
1 public List<E> subList(int fromIndex, int toIndex) { 2 return (this instanceof RandomAccess ? 3 new RandomAccessSubList<>(this, fromIndex, toIndex) : 4 new SubList<>(this, fromIndex, toIndex)); 5 }
subList是由AbstractList實現的,它根據是否是能夠隨機存取來提供不一樣的SubList實現方式。因爲RandomAccessSubList也是SubList的子類,因此全部的操做都是由SubList類實現的。來看一下SubList類的代碼:加密
class SubList<E> extends AbstractList<E> { private final AbstractList<E> l; private final int offset; private int size; SubList(AbstractList<E> list, int fromIndex, int toIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); if (toIndex > list.size()) throw new IndexOutOfBoundsException("toIndex = " + toIndex); if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); l = list; offset = fromIndex; size = toIndex - fromIndex; this.modCount = l.modCount; } public E get(int index) { rangeCheck(index); checkForComodification(); return l.get(index+offset); } public void add(int index, E element) { rangeCheckForAdd(index); checkForComodification(); l.add(index+offset, element); this.modCount = l.modCount; size++; } /*其他代碼省略,能夠在AbstractList.java文件中自行查看*/ }
不難發現,subList返回的SubList類並無生成一個數組或者鏈表,它自己只是原列表的一個視圖而已,所以全部的修改動做都反映在了原列表上。spa
看一個簡單的需求,一個有100個元素,如今要刪除索引位置爲20~30的元素。能夠經過以下的代碼實現:
1 public static void main(String[] args) { 2 List<Integer> initData = Collections.nCopies(100, 0); 3 4 ArrayList<Integer> list = new ArrayList<>(initData); 5 6 list.subList(20, 30).clear(); 7 }
可是,這個時候就不要再對原列表進行操做了。來看下邊的代碼:
1 public static void main(String[] args) { 2 List<Integer> initData = Collections.nCopies(100, 0); 3 4 ArrayList<Integer> list = new ArrayList<>(initData); 5 List<Integer> subList = list.subList(20, 30); 6 list.add(0); 7 8 System.out.print("原列表長度:" + list.size()); 9 System.out.print("子列表長度:" + subList.size()); 10 }
程序運行時,size方法報ConcurrentModificationException。由於subList取出的磊表示原列表的一個視圖,原數據集修改了,可是subList取出的子列表不會從新生成,再後面對子列表進行操做時,就會檢測到修改計數器與預期的不相同,因而拋出併發修改異常。問題最終仍是在子列表提供的size方法的檢查上:
public int size() { checkForComodification(); return size; } private void checkForComodification() { if (this.modCount != l.modCount) throw new ConcurrentModificationException(); }
modCount是在SubList子列表的構造函數中賦值的,其值等於生成子列表時原列表的修改次數。在生成子列表後再修改原列表,1.modCount必然比modCount大1,再也不相等,因而拋出併發修改異常。
SubList的其餘方法也會檢查修改計數器。對於子列表操做,子列表的modCount老是跟隨原列表進行更新。
能夠在生成子列表後,經過 Collections.unmodifiableList 設置原列表爲只讀狀態,在後續的操做中,對原列表只進行讀操做,對子列表進行讀寫操做。防護式編程就是教咱們如此作的。
1 public static void main(String[] args) { 2 List<Integer> initData = Collections.nCopies(100, 0); 3 4 List<Integer> list = new ArrayList<>(initData); 5 List<Integer> subList = list.subList(20, 30); 6 //設置list爲只讀狀態 7 list = Collections.unmodifiableList(list); 8 }
1 public static void main(String[] args) { 2 3 List<String> list1 = new ArrayList<>(); 4 list1.add("A"); 5 list1.add("B"); 6 7 List<String> list2 = new ArrayList<>(); 8 list2.add("A"); 9 list2.add("B"); 10 11 list1.addAll(list2); 12 }
1 list1.retainAll(list2);
注意:retainAll方法會刪除list1中沒有在list2中出現的元素
全部屬於A但不屬於B的元素組成的集合,叫作A與B的差集。
1 //去除重複元素 2 list2.removeAll(list1); 3 //取並集 4 list1.addAll(list2);
Collections.shuffle(list1);
shuffle方法能夠用在一下方面:
如:遊戲中打怪,修行,寶物分配的分配策略
發送端發送一組數據,先隨機打亂順序,加密發送;接收端解密後自行排序便可。