1. 程式人生 > >Java集合框架之Collection例項解析

Java集合框架之Collection例項解析

0、集合引入

1)集合的由來?

Java是面向物件程式語言,經常需要操作很多物件,必要時需儲存物件(對Java語言而言,儲存的通常是物件的引用,以達到複用或管理等目的),常見容器如陣列和StringBuffer(執行緒安全但效率較低,為了提高效率而引進StringBuilder)。

通常陣列的長度固定,所以不適合做變化的需求(可以手動去重新分配調整,較麻煩),而StringBuffer(或StringBuilder)儲存元素為字串,皆不符合儲存任意元素的要求。因此集合就應運而生了。

2)集合和陣列的區別?

  • 1 長度限制之別

    • 陣列長度是固定不變的
    • 集合的大小是可動態變化的
  • 2 儲存型別之別

    • 一個數組儲存的元素可以是基本型別,也可以是引用型別,且只能儲存同一種類型的元素
    • 一個集合儲存的元素只能是引用型別,但集合可以儲存不同型別的元素(但集合一般儲存同一種類型,可以用泛型加以控制)
  • 3 訪問元素方式

    • 陣列是根據索引來獲取元素的
    • 集合通常會提供一個迭代器來方便訪問元素

3)java集合框架初窺

這裡寫圖片描述

  • 從圖上我們可以清晰的看到Java集合分為兩大類:
    • 以Collection介面為規範衍生的單列集合,儲存單列資料或物件
    • 以Map介面為規範衍生的雙列集合,儲存key-value對映或關聯關係
  • iterator 是迭代器,用於遍歷集合元素

本文著重來寫Collection集合。Map集合介紹見

Java集合框架之Map例項解析

:圖片來源於網路。類已經很全了,就不贅畫了。

1、Collection之繼承體系

Collection<E> 介面是所有單列集合的共同父介面,下面列出了常用的Collection子類集合及其繼承關係。

Collection
    |-----List  有序(儲存順序和取出順序一致),可重複

        |----ArrayList ,執行緒不安全,底層使用陣列實現,查詢快,增刪慢。效率高。
                每次容量不足時,自增長度的一半,如下原始碼可知
                  int newCapacity = oldCapacity + (oldCapacity >> 1);
        |----LinkedList , 執行緒不安全,底層使用連結串列實現,查詢慢,增刪快。效率高

        |----Vector , 執行緒安全,底層使用陣列實現,查詢快,增刪慢。效率低
                每次容量不足時,預設自增長度的一倍(如果不指定增量的話),如下原始碼可知
                   int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    |-----Set   元素唯一
    一個不包含重複元素的 collection。更確切地講,set 不包含滿足 e1.equals(e2) 的元素對 e1 和 e2,並且最多包含一個 null 元素。

        |--HashSet 底層是由HashMap實現的,通過物件的hashCode方法與equals方法來保證插入元素的唯一性,無序(儲存順序和取出順序不一致)。

            |--LinkedHashSet 底層資料結構由雜湊表和連結串列組成。雜湊表保證元素的唯一性,連結串列保證元素有序。(儲存和取出是一致)

        |--TreeSet 基於 TreeMap 的 NavigableSet 實現。使用元素的自然順序對元素進行排序,或者根據建立 set 時提供的 Comparator 進行排序,具體取決於使用的構造方法。 元素唯一。

2、Collection泛型介面

方法摘要

 boolean add(E e) 
              確保此 collection 包含指定的元素(可選操作)。 
     boolean addAll(Collection<? extends E> c) 
              將指定 collection 中的所有元素都新增到此 collection 中(可選操作)。 
     void clear() 
              移除此 collection 中的所有元素(可選操作)。 
     boolean contains(Object o) 
              如果此 collection 包含指定的元素,則返回 trueboolean containsAll(Collection<?> c) 
              如果此 collection 包含指定 collection 中的所有元素,則返回 trueboolean equals(Object o) 
              比較此 collection 與指定物件是否相等。 
     int hashCode() 
              返回此 collection 的雜湊碼值。 
     boolean isEmpty() 
              如果此 collection 不包含元素,則返回 true。 
     Iterator<E> iterator() 
              返回在此 collection 的元素上進行迭代的迭代器。 
     boolean remove(Object o) 
              從此 collection 中移除指定元素的單個例項,如果存在的話(可選操作)。 
     boolean removeAll(Collection<?> c) 
              移除此 collection 中那些也包含在指定 collection 中的所有元素(可選操作)。 
     boolean retainAll(Collection<?> c) 
              僅保留此 collection 中那些也包含在指定 collection 的元素(可選操作)。 
     int size() 
              返回此 collection 中的元素數。 
     Object[] toArray() 
              返回包含此 collection 中所有元素的陣列。 
    <T> T[] 
     toArray(T[] a) 

使用Collection示例

public class CollectionReview {
    public static void main(String[] args) {
        test1();

    }

    private static void test1() {
        // Collection<E>為介面,使用多型進行建立
        Collection<String> collection = new Vector<>();
        collection.add("gogogo");
        collection.add("pap");
        collection.add("niko");
        collection.add("kitty");

        Collection<String> coll = new ArrayList<>();
        coll.add("niko");
        coll.add("kitty");
        coll.add("pecuyu");

        // collection.clear(); // 清空集合
         //System.out.println(collection.isEmpty()); // 集合是否為空

        // int size = collection.size(); // 獲取集合大小
        // System.out.println(size);  

        // boolean contains = collection.contains("niko"); // 是否包含另一個元素
        // System.out.println(contains);
        //boolean containsAll = collection.containsAll(coll); //是否完全包含另一個集合
        //System.out.println(containsAll);

        // collection.remove("kitty");   // 刪除第一個匹配項,刪除了匹配項則返回true
        // boolean removeAll = collection.removeAll(coll);  // 刪除與指定集合有交集的部分,原集合有改變就返回true
        // System.out.println(removeAll);

        //boolean retainAll = collection.retainAll(coll);// 保留與指定集合有交集的部分,原集合有改變就返回true
        //System.out.println(retainAll);

    // iterator 迭代器, 方式1
        Iterator<String> iterator = collection.iterator();
        while(iterator.hasNext()){
            System.out.print(iterator.next()+" ");
        }
        System.out.println("\n"+"-------------------");

    // 方式2 ,for迴圈完iterator1就會被銷燬,節約記憶體提高效率
        for (Iterator<String> iterator1 = collection.iterator(); iterator1.hasNext(); ) {
            System.out.print(iterator1.next()+" ");

        }
        System.out.println("\n"+"-------------------");


        Object[] array = collection.toArray();  // 轉化為object陣列
        for (Object string : array) {
            System.out.print(string+" ");
        }
        System.out.println("\n"+"-------------------");
        String[] arr=new String[collection.size()];
        String[] array2 = collection.toArray(arr);  // 指定要轉化的陣列型別
        for (String string : array2) {
            System.out.print(string+" ");
        }
    }

3、List泛型介面

繼承自Collection

特有方法(相對於Collection)

 void add(int index, E element) 
          在列表的指定位置插入指定元素(可選操作)。 
 boolean addAll(int index, Collection<? extends E> c) 
          將指定 collection 中的所有元素都插入到列表中的指定位置(可選操作)。  
 E get(int index) 
          返回列表中指定位置的元素。  
 int indexOf(Object o) 
          返回此列表中第一次出現的指定元素的索引;如果此列表不包含該元素,則返回 -1int lastIndexOf(Object o) 
          返回此列表中最後出現的指定元素的索引;如果列表不包含此元素,則返回 -1。 
 ListIterator<E> listIterator() 
          返回此列表元素的列表迭代器(按適當順序)。 
 ListIterator<E> listIterator(int index) 
          返回列表中元素的列表迭代器(按適當順序),從列表的指定位置開始。 
 E remove(int index) 
          移除列表中指定位置的元素(可選操作)。 
 E set(int index, E element) 
          用指定元素替換列表中指定位置的元素(可選操作)。 
 List<E> subList(int fromIndex, int toIndex) 
          返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之間的部分檢視。 

3.1、ArrayList類

繼承自AbstractList,實現了Iterable, Collection, List,Cloneable, Serializable

每次容量不足時,自增長度的一半

int newCapacity = oldCapacity + (oldCapacity >> 1);

1 構造方法

    ArrayList() 
          構造一個初始容量為 10 的空列表(每次遞增容量的一半)
    ArrayList(Collection<? extends E> c) 
          構造一個包含指定 collection 的元素的列表,這些元素是按照該 collection 的迭代器返回它們的順序排列的 
    ArrayList(int initialCapacity) 
          構造一個具有指定初始容量的空列表

2 特有方法(相對於List)

void ensureCapacity(int minCapacity) 
          如有必要,增加此 ArrayList 例項的容量,以確保它至少能夠容納最小容量引數所指定的元素數。 
          返回此列表中最後一次出現的指定元素的索引,或如果此列表不包含索引,則返回 -1protected  void removeRange(int fromIndex, int toIndex) 
          移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之間的所有元素。 

3 ArrayList使用示例

public class ArrayListReview {
    public static void main(String[] args) {
        ArrayList<Info> infosList=new ArrayList<>();
        infosList.add(new Info(0, "aaa"));
        infosList.add(new Info(1, "bbb"));
        infosList.add(new Info(2, "ccc"));
        infosList.add(new Info(3, "ddd"));
        infosList.add(1, new Info(4, "eee")); // 按索引插入到指定位置

        // foreach遍歷輸出
        for (Info info : infosList) {
            System.out.println(info);
        }
        System.out.println("------------------------");

        // 擷取子List
        List<Info> subList = infosList.subList(1, 3);
        subList.add(new Info(30, "fly"));
        printList(subList);

        ArrayList<Info> newInfosList=new ArrayList<>();
        newInfosList.add(new Info(11, "qqq"));
        newInfosList.add(new Info(12, "www"));

        ArrayList<String> ss=new ArrayList<>();
//      infosList.addAll(newInfosList);  // 新增一個指定集合到原集合最後,注意兩個集合的泛型引數一致
        infosList.addAll(2,newInfosList); // 將指定集合插入到指定位置
        //printList(infosList);

        Info info = infosList.get(2);  // 取出指定位置的元素
        System.out.println(info);

        infosList.set(0, new Info(10, "rrr"));   // 替換指定索引位置的元素
        //printList(infosList);

        int index = infosList.indexOf(info);  //根據元素獲取元素第一次出現的索引,不存在則返回-1
        int lastIndex = infosList.lastIndexOf(info); // 取出元素的最後一個匹配項的索引
        int indexOf = infosList.indexOf(new Info(4,"eee")); // 重寫了Info類的hashCode與equals方法,用於判斷兩個物件是否相同
        System.out.println("index="+indexOf);
        //printList(infosList);

        // 通過反射拿到的removeRange方法
        removeRange(infosList, 1, 3);
        //printList(infosList);

        // listIterator從前往後迭代
        ListIterator<Info> listIterator = infosList.listIterator();
        while(listIterator.hasNext()){
            // 最後丟擲錯誤,java.util.NoSuchElementException,不要每次取都掉用next方法,它每呼叫一次,迭代器指標向前移動一位
//          System.out.println("id="+listIterator.next().getId()
//                  +"adress="+listIterator.next().getAdress()); 

            Info next = listIterator.next();  // 正確做法,呼叫一次要取出元素,然後操作屬性
            System.out.println("id="+next.getId()
                    +" adress="+next.getAdress()); 
        }

        // 往前迭代,必須在往後迭代之後用
        while(listIterator.hasPrevious()){  // 當有上一個元素時
            Info previous = listIterator.previous();  // 獲取上一個元素
            System.out.println("id="+previous.getId()+" adresss="+previous.getAdress());
        }

        // 通過陣列來轉化成一個List,雖然可以把陣列轉成集合,但是集合的長度不能改變。
        String[] a=new String[]{"hello","world","just","do","it"};
        List<String> asList = Arrays.asList(a);
        //asList.add("gogogo");  //不可修改asList,會丟擲UnsupportedOperationException

        // 泛型使用 
//      ArrayList<Object> l=new ArrayList<String>();// 不行
//      ArrayList<ArrayList> lll=new ArrayList<List>(); // 不行
//      ArrayList<List> lll=new ArrayList<ArrayList>(); // 不行
//      ArrayList l=new ArrayList<String>(); // 可行
//      ArrayList<String> l=new ArrayList<>(); // 可行
//      ArrayList ll=new ArrayList();  // 可行
    }

    // 列印輸出
    public static <E> void printList(List<E> list) {
        for (E e : list) {
            System.out.println(e);
        }
        System.out.println("------------------------");
    }
}

4 ArrayList的removeRange的使用

removeRange方法是protect訪問許可權,無法直接使用,可以通過反射拿到它(反射相關不熟悉的可以參考 Java反射機制

    /**
     * 通過反射呼叫ArrayList的removeRange方法
     * @param list  用於刪除元素的list
     * @param fromIndex 起始刪除索引,包含
     * @param toIndex   結束刪除索引,不包含
     */
    public static <E> void removeRange(ArrayList<E> list,int fromIndex, int toIndex) {
        try {
            // 拿到ArrayList的Class物件
            Class<?> clazz = Class.forName("java.util.ArrayList");
            // 通過clazz物件拿到removeRange方法,引數為(int,int)
            Method declaredMethod = clazz.getDeclaredMethod("removeRange", int.class,int.class);
            // 將方法的訪問許可權設定為可訪問
            declaredMethod.setAccessible(true); 
            //  呼叫removeRange方法
            declaredMethod.invoke(list,fromIndex,toIndex);  
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

Info類如下

public class Info   {
    private int id;
    private String adress;

    public Info(int id, String adress) {
        super();
        this.id = id;
        this.adress = adress;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAdress() {
        return adress;
    }

    public void setAdress(String adress) {
        this.adress = adress;
    }

    @Override
    public String toString() {
        return "Info [id=" + id + ", adress=" + adress + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((adress == null) ? 0 : adress.hashCode());
        result = prime * result + id;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Info other = (Info) obj;
        if (adress == null) {
            if (other.adress != null)
                return false;
        } else if (!adress.equals(other.adress))
            return false;
        if (id != other.id)
            return false;
        return true;
    }
}

3.2、LinkedList類

繼承自AbstractSequentialList,實現了List, Deque, Cloneable, Serializable

底層使用連結串列實現,查詢慢,增刪快。執行緒不安全,效率高

1 構造方法

 LinkedList() 
          構造一個空列表。 
 LinkedList(Collection<? extends E> c) 
          構造一個包含指定 collection 中的元素的列表,這些元素按其 collection 的迭代器返回的順序排列。

2 特有方法(相對於List)

實現了Deque, Queue ,獲得了他們的方法,關係如下

Queue 方法 等效 Deque 方法
add(e) addLast(e)
offer(e) offerLast(e)
remove() removeFirst()
poll() pollFirst()
element() getFirst()
peek() peekFirst()
堆疊方法(Deque作堆疊) 等效 Deque 方法
push(e) addFirst(e)
pop() removeFirst()
peek() peekFirst()

 void addFirst(E e) 
          將指定元素插入此列表的開頭。 
 void addLast(E e) 
          將指定元素新增到此列表的結尾。
 Iterator<E> descendingIterator() 
          返回以逆向順序在此雙端佇列的元素上進行迭代的迭代器。 
 E element() 
          獲取但不移除此列表的頭(第一個元素)。     
 E getFirst() 
          返回此列表的第一個元素。 
 E getLast() 
          返回此列表的最後一個元素。 
 boolean offer(E e) 
          將指定元素新增到此列表的末尾(最後一個元素)。 
 boolean offerFirst(E e) 
          在此列表的開頭插入指定的元素。 
 boolean offerLast(E e) 
          在此列表末尾插入指定的元素。 
 E peek() 
          獲取但不移除此列表的頭(第一個元素)。 
 E peekFirst() 
          獲取但不移除此列表的第一個元素;如果此列表為空,則返回 null。 
 E peekLast() 
          獲取但不移除此列表的最後一個元素;如果此列表為空,則返回 null。 
 E poll() 
          獲取並移除此列表的頭(第一個元素) 
 E pollFirst() 
          獲取並移除此列表的第一個元素;如果此列表為空,則返回 null。 
 E pollLast() 
          獲取並移除此列表的最後一個元素;如果此列表為空,則返回 null。 
 E pop() 
          從此列表所表示的堆疊處彈出一個元素。 
 void push(E e) 
          將元素推入此列表所表示的堆疊。 
 E removeFirst() 
          移除並返回此列表的第一個元素。 
 E removeLast() 
          移除並返回此列表的最後一個元素。 
 boolean removeFirstOccurrence(Object o) 
          從此列表中移除第一次出現的指定元素(從頭部到尾部遍歷列表時)。 
 boolean removeLastOccurrence(Object o) 
          從此列表中移除最後一次出現的指定元素(從頭部到尾部遍歷列表時)。 

3 LinkedList使用示例

public class LinkListReview {
    public static void main(String[] args) {
        LinkedList<String> list=new LinkedList<>();
        list.addFirst("qqq"); //  將指定元素插入此列表的開頭。
        list.addLast("eee");    // 將指定元素新增到此列表的結尾。
        list.addFirst("www"); // 到此list的排序為: www qqq eee
//      list.set(2, "ttt");  // 替換指定位置的元素,注意索引要小於list的size

        Iterator<String> descendingIterator = list.descendingIterator(); // 反向迭代器
        while (descendingIterator.hasNext()) {
            System.out.print(descendingIterator.next()+" ");
        }
        System.out.println("\n"+"-------------------------");

        // ListIterator迭代,指定迭代的起始位置
        ListIterator<String> listIterator = list.listIterator(1); // 正反向都可迭代,反向迭代須在正向之後進行,
        while(listIterator.hasNext()){
            System.out.print(listIterator.next()+" ");
        }
        System.out.println("\n"+"-------------------------");

        // 元素的獲取與新增
        String element = list.element(); // 獲取但不移除此列表的頭(第一個元素)
        System.out.println(element);
        String first = list.getFirst();  // 返回此列表的第一個元素
        String last = list.getLast();   //  返回此列表的最後一個元素
        System.out.println("first="+first+" last="+last);

        System.out.println("peek="+list.peek());//  peek() 獲取但不移除此列表的頭(第一個元素)。 
        System.out.println("peekFirst="+list.peekFirst()); //E peekFirst() 獲取但不移除此列表的第一個元素;如果此列表為空,則返回 null。 
        System.out.println("peekLast="+list.peekLast()); ////E peekLast()  獲取但不移除此列表的最後一個元素;如果此列表為空,則返回 null。 
        printList(list);

        System.out.println("poll="+list.poll()); // poll()  獲取並移除此列表的頭(第一個元素) 
        System.out.println("pollFirst="+list.pollFirst());//E pollFirst() 獲取並移除此列表的第一個元素;如果此列表為空,則返回 null。 
        System.out.println("pollLast="+list.pollLast());//E pollLast()  獲取並移除此列表的最後一個元素;如果此列表為空,則返回 null。 
        printList(list);

        list.push("push"); //void push(E e)  將元素推入此列表所表示的堆疊,相當於addFirst(E e)。此方法繼承自Deque
        list.push("push1");
        list.push("push2");
        list.pop(); //E pop() 從此列表所表示的堆疊處彈出一個元素。 若list的集合為空,則丟擲//E pop() 從此列表所表示的堆疊處彈出一個元素。 
        printList(list);


        list.offer("offer"); //    將指定元素新增到此列表的末尾(最後一個元素)。
        list.offerFirst("offerFirst"); //在此列表的開頭插入指定的元素。
        list.offerLast("offerLast");    //在此列表末尾插入指定的元素。
        printList(list);

        // removeFirstOccurrence刪除第一個匹配項,removeLastOccurrence刪除最後一個匹配項 都是順序遍歷方向
        System.out.println("removeFirstOccurrence="+list.removeFirstOccurrence("offerFirst"));
        System.out.println("removeLastOccurrence="+list.removeLastOccurrence("offerLast"));
        printList(list);

        // 通過集合的方式山刪除要刪除的元素
        LinkedList<String> dyingList=new LinkedList<>();
        for(ListIterator<String> li=list.listIterator();li.hasNext();){
            String next = li.next();
            if (next.equals("push")) {
            //  list.removeFirstOccurrence(next); // 不能再迴圈時修改,丟擲併發修改異常ConcurrentModificationException
                dyingList.add(next);  // 將要刪除的元素儲存起來以備刪除
            }
        }
        list.removeAll(dyingList); // 刪除要移除的元素
        printList(list);

        // ListIterator進行遍歷,並進行修改
        for(ListIterator<String> it=list.listIterator();it.hasNext();){
            String next=it.next();
            if(next.equals("offer")){
            //  it.remove();  // 移除當前,即next所指元素
            //  it.set("newOffer"); // 替換當前,即next所指元素
                it.add("newHere"); // 新增元素,在next所指元素之後

            }
        }
        printList(list);

        // for迴圈通過list進行修改
        for(int i=0;i<list.size();i++){ 
            if(list.get(i).equals("push1")){
                list.remove(i);
            }
        }
        printList(list);
    }


    public static <E> void printList(List<E> list) {
        for (E e : list) {
            System.out.print(e+" ");
        }
        System.out.println("\n-------------------------");
    }
}

3.3、Vector類

繼承自AbstractList,實現了 List,Cloneable, Serializable介面

每次容量不足時,預設自增長度的一倍(如果不指定增量的話)

  int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);

3.31 構造方法摘要

    Vector() 
          構造一個空向量,使其內部資料陣列的大小為 10,其標準容量增量為零。 
    Vector(Collection<? extends E> c) 
          構造一個包含指定 collection 中的元素的向量,這些元素按其 collection 的迭代器返回元素的順序排列。 
    Vector(int initialCapacity) 
          使用指定的初始容量和等於零的容量增量構造一個空向量。 
    Vector(int initialCapacity, int capacityIncrement) 
          使用指定的初始容量和容量增量構造一個空的向量。 

3.32 特有方法摘要


 void addElement(E obj) 
          將指定的元件新增到此向量的末尾,將其大小增加 1void copyInto(Object[] anArray) 
          將此向量的元件複製到指定的陣列中。 
 E elementAt(int index) 
          返回指定索引處的元件。 
 Enumeration<E> elements() 
          返回此向量的元件的列舉。 
 void ensureCapacity(int minCapacity) 
          增加此向量的容量(如有必要),以確保其至少能夠儲存最小容量引數指定的元件數。 
 E firstElement() 
          返回此向量的第一個元件(位於索引 0) 處的項)。 
 void insertElementAt(E obj, int index) 
          將指定物件作為此向量中的元件插入到指定的 index 處。 
 E lastElement() 
          返回此向量的最後一個元件。 
 void removeAllElements() 
          從此向量中移除全部元件,並將其大小設定為零。 
 boolean removeElement(Object obj) 
          從此向量中移除變數的第一個(索引最小的)匹配項。 
 void removeElementAt(int index) 
          刪除指定索引處的元件。 
 protected  void removeRange(int fromIndex, int toIndex) 
          從此 List 中移除其索引位於 fromIndex(包括)與 toIndex(不包括)之間的所有元素。 
 void setElementAt(E obj, int index) 
          將此向量指定 index 處的元件設定為指定的物件。 
 void setSize(int newSize) 
          設定此向量的大小。 

3.33 Vector使用示例

public class VectorReview {
    public static void main(String[] args) {
        Vector<String> vector=new Vector<>();
        vector.addElement("e1");
        vector.addElement("e2");
        vector.addElement("e3");
        vector.addElement("e4");
        vector.addElement("e5");
        vector.add(3, "e6");  //在指定位置新增元素,非覆蓋

        printList(vector);

        // copyInto將內容拷貝到一個數組中
        String[] anArray=new String[vector.size()];  // 注意陣列長度不要小於vector的size
        vector.copyInto(anArray);
        for (String string : anArray) {
            System.out.print(string+"  ");
        }
        System.out.println("\n--------");

        // 返回指定位置的元素
        String elementAt = vector.elementAt(2);
        System.out.println(elementAt);
        System.out.println(vector.firstElement()); // 返回此向量的第一個元件,索引0的元素
        System.out.println(vector.lastElement()); //返回此向量的最後一個元件

        // 刪除元素
        //vector.removeAllElements(); //  從此向量中移除全部元件,並將其大小設定為零。
        System.out.println(vector.removeElement("e5")); //   從此向量中移除變數的第一個(索引最小的)匹配項。
        vector.removeElementAt(2);  //  刪除指定索引處的元件。
        vector.setElementAt("yyy", 3);  //   將此向量指定 index 處的元件設定為指定的物件。注意index要小於vector的size
        printList(vector);

        // 返回此向量的元件的列舉
        Enumeration<String> elements = vector.elements();
        while(elements.hasMoreElements()){
            System.out.print(elements.nextElement()+" ");
        }
        System.out.println("\n--------");   
    }

    public static void printList(List<String> list) {
        for (String string : list) {
            System.out.print(string+" ");
        }
        System.out.println("\n-----------------");
    }

3.4 併發修改異常

1:出現的現象
    迭代器遍歷集合,集合修改集合元素
2:原因
    迭代器是依賴於集合的,而集合的改變迭代器並不知道。
3:解決方案
    1:迭代器遍歷,迭代器修改(ListIterator)
            元素新增在剛才迭代的位置
    2:集合遍歷(普通for迴圈),集合修改
            元素新增在集合的末尾
    3:遍歷集合,將要刪除的元素新增到另一個集合,然後原集合通過removeAll刪除待刪除的集合

方案3示例

// 通過集合的方式山刪除要刪除的元素
        LinkedList<String> dyingList=new LinkedList<>();
        for(ListIterator<String> li=list.listIterator();li.hasNext();){
            String next = li.next();
            if (next.equals("push")) {
            //  list.removeFirstOccurrence(next); // 不能再迴圈時修改,丟擲併發修改異常ConcurrentModificationException
                dyingList.add(next);  // 將要刪除的元素儲存起來以備刪除
            }
        }
        list.removeAll(dyingList); // 刪除要移除的元素

3.5 Iterator的替代品 -增強for迴圈

(1)for迴圈的一種,另一種書寫形式
(2)書寫格式:
    for(元素的資料型別 變數名 : 陣列或者Collection集合的物件) {
        使用該變數即可,該變數其實就是陣列或者集合中的元素。
    }
(3)好處:
    簡化了陣列和集合的遍歷
(4)弊端
    增強for迴圈的目標不能為null。建議在使用前,先判斷是否為null。並且,也沒有元素的index位置
// 增強for
for (String s : array) {
    System.out.println(s);
}

反編譯可知增強是通過Iterator來實現的

for (Iterator iterator = array.iterator(); iterator.hasNext(); System.out.println(s))
    s = (String)iterator.next();

4. Set泛型介面

一個不包含重複元素的 collection,實現了Collection, Iterable 介面,常見子類 HashSet, LinkedHashSet, TreeSet

方法摘要

 相對於Collection沒有特殊方法,略

4.1 TreeSet

TreeSet 基於 TreeMap 的 NavigableSet 實現。非同步,排序,元素唯一。通過Collections.synchronizedSortedSet 方法來“包裝”該 TreeSet實現同步

必須保證元素可排序性,如下兩種方法

  ① 使用元素的自然順序對元素進行排序(元素要實現Comparable介面並重寫compare方法)。
  ② 根據建立 set 時提供的 Comparator 進行排序。

4.11 構造方法摘要

TreeSet() 
          構造一個新的空 set,該 set 根據其元素的自然順序進行排序。 
 TreeSet(Collection<? extends E> c) 
          構造一個包含指定 collection 元素的新 TreeSet,它按照其元素的自然順序進行排序。 
 TreeSet(Comparator<? super E> comparator) 
          構造一個新的空 TreeSet,它根據指定比較器進行排序。 
 TreeSet(SortedSet<E> s) 
          構造一個與指定有序 set 具有相同對映關係和相同排序的新 TreeSet。 

4.12 特有方法摘要 (相對於Set)

 E ceiling(E e) 
          返回此 set 中大於等於給定元素的最小元素;如果不存在這樣的元素,則返回 null。 

 Comparator<? super E> comparator() 
          返回對此 set 中的元素進行排序的比較器;如果此 set 使用其元素的自然順序,則返回 null。 
 Iterator<E> descendingIterator() 
          返回在此 set 元素上按降序進行迭代的迭代器。 
 NavigableSet<E> descendingSet() 
          返回此 set 中所包含元素的逆序檢視。 
 E first() 
          返回此 set 中當前第一個(最低)元素。 
 E floor(E e) 
          返回此 set 中小於等於給定元素的最大元素;如果不存在這樣的元素,則返回 null。 
 SortedSet<E> headSet(E toElement) 
          返回此 set 的部分檢視,其元素嚴格小於 toElement。 
 NavigableSet<E> headSet(E toElement, boolean inclusive) 
          返回此 set 的部分檢視,其元素小於(或等於,如果 inclusive 為 true)toElement。 
 E higher(E e) 
          返回此 set 中嚴格大於給定元素的最小元素;如果不存在這樣的元素,則返回 null。 
 Iterator<E> iterator() 
          返回在此 set 中的元素上按升序進行迭代的迭代器。 
 E last() 
          返回此 set 中當前最後一個(最高)元素。 
 E lower(E e) 
          返回此 set 中嚴格小於給定元素的最大元素;如果不存在這樣的元素,則返回 null。 
 E pollFirst() 
          獲取並移除第一個(最低)元素;如果此 set 為空,則返回 null。 
 E pollLast() 
          獲取並移除最後一個(最高)元素;如果此 set 為空,則返回 null。 
 NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) 
          返回此 set 的部分檢視,其元素範圍從 fromElement 到 toElement。 
 SortedSet<E> subSet(E fromElement, E toElement) 
          返回此 set 的部分檢視,其元素從 fromElement(包括)到 toElement(不包括)。 
 SortedSet<E> tailSet(E fromElement) 
          返回此 set 的部分檢視,其元素大於等於 fromElement。 
 NavigableSet<E> tailSet(E fromElement, boolean inclusive) 
          返回此 set 的部分檢視,其元素大於(或等於,如果 inclusive 為 true)fromElement。 

4.13 TreeSet使用示例

public class TreeSetReview {
    public static void main(String[] args) {
//      test1();
        test2();
    }

    /**
     * 自然排序
     */
    private static void test1() {
        TreeSet<String> treeSet=new TreeSet<String>();
        treeSet.add("a");
        treeSet.add("d");
        treeSet.add("b");
        treeSet.add("e");
        treeSet.add("c");

        for (String string : treeSet) {
            System.out.println(string);
        }
    }

    /**
     * 
     * TreeSet新增自定義物件時滿足其一 ①構造時傳入比較器 ②實現Comparable介面並重寫compare方法,否則丟擲異常
     *  java.lang.ClassCastException:
     *  com.yu.bean.Info cannot be cast to java.lang.Comparable
     */
    private static void test2() {
        TreeSet<Info> infosSet =new TreeSet<Info>(new Comparator<Info>() { // 傳入比較器,保證順序

            @Override
            public int compare(Info o1, Info o2) {
                int num=o1.getId()-o2.getId();
                num = num==0?o1.hashCode()-o2.hashCode():num;
                return num;
            }
        }) ;

        infosSet.add(new Info(0, "qqq"));
        infosSet.add(new Info(1, "wew"));
        infosSet.add(new Info(3, "ete"));
        infosSet.add(new Info(2, "bjk"));
        infosSet.add(new Info(1, "wew")); // 重複元素,compare方法返回0,不會被插入到TreeSet

        for (Info info : infosSet) {
            System.out.println(info);
        }
//      output:
//      Info [id=0, adress=qqq]
//      Info [id=1, adress=wew]
//      Info [id=2, adress=bjk]
//      Info [id=3, adress=ete]

//  可以看出,Comparator保證了元素的有序性,重複元素將不會被新增到TreeSet

    }
}

4.2 LinkedHashSet

LinkedHashSet,