java集合-List



  1. List判斷兩個對象相等只經過equals方法比較返回true便可。
public class A {
    @Override
    public boolean equals(Object arg0) {
        return true;
    }
}
public class SameAListTest {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        //[1, 2, 3]
        System.out.println(list);
        list.remove(new A());
        //[2, 3]
        System.out.println(list);
        list.remove(new A());
        //[3]
        System.out.println(list);
    }
}
  • 從上面程序能夠看出,當程序試圖刪除一個A對象,List將會調用該A對象的equals方法依次與集合元素進行比較,若是該equals方法以某個集合元素做爲參數時返回true,List將會刪除該元素,A重寫了equals方法,該方法老是返回true。
  • 當調用List的set(int index,Object object)方法來改變List集合指定所引處的元素時,指定的索引必須是List集合的有效索引。例如集合長度是4,就不能指定替換索引爲4處的元素--也就是說,set(int index,Object object)方法不會改變List集合的長度。
  • List還額外提供了一個listIterator方法,該方法返回一個ListIterator對象,ListIterator接口繼承了Iterator接口,提供了專門操做List的方法。
public class ListIterators {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("123");
        list.add("231");
        list.add("132");
        /*正向迭代
         * Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }*/
        /*//從指定的索引之後的元素進行迭代   Lambda迭代
        ListIterator<String> listIterator = list.listIterator(1);
        //231  132
        listIterator.forEachRemaining((e) -> System.out.println(e));*/
        
        ListIterator<String> iterator = list.listIterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            System.out.println(next);
            if ("132".equals(next)) {
                iterator.add("新添加的");
            }
            
        }
        System.out.println("反向迭代 +++++++++++++++++++++");
        while (iterator.hasPrevious()) {
            System.out.println(iterator.previous());
        }
        //[123, 231, 132, 新添加的]
        System.out.println(list);
        /*
         * 123
           231
           132
           反向迭代 +++++++++++++++++++++
           新添加的
           132
           231
           123
           [123, 231, 132, 新添加的]
         */
    }
}
  • ListIterator與Iterator相比,ListIterator是反向迭代,Iterator是正向迭代,並且ListIterator還能夠經過add方法向List集合中添加元素,Iterator只能刪除元素、

ArrayList和Vector實現類

  • ArrayList和Vector類都是基於數組實現的List類,因此ArrayList和Vector類分裝了一個動態的,容許再分配的Object[]數組。ArrayList或Vector對象使用initialCapacity參數來設置該數組的長度,當向ArrayList或Vector中添加元素超出了該數組的長度時,他們的initialCapacity會自動增長。
  • ArrayList和Vector的區別是:ArrayList是線程不安全的,當多個線程訪問同一個ArrayList集合時,若是有超過一個線程修改了ArrayList集合,則程序必須手動保證該集合的同步性,但Vector集合則是線程安全的,無須程序保證該集合的同步性。所以Vector是線程安全的,因此Vector的性能比ArrayList的性能要低;
  • Vector提供了Stack子類,它用於模擬棧這種數據結構,棧筒倉是指後進先出LIFO的容器,最後push進棧的元素,將最早被pop出棧,出入棧的都是Object,
  • 若是程序須要使用棧這種數據結構,則能夠考慮ArrayDeque。
  • ArrayDeque底層是基於數組實現的,所以性能很好。
public class ArrayListAndVector {
    public static void main(String[] args) {
        Stack<String> vector = new Stack<>();
        vector.push("1");
        vector.push("2");
        vector.push("3");
        while (!vector.empty()) {
            System.out.println(vector.pop());// 3 2 1 
            //System.out.println(vector.peek());  會死循環,由於棧內不會彈出因此判斷會一直執行。
        }
    }
}

固定長度的List

  • Arrays提供了asList(Object...a)方法,該方法能夠把一個數組或指定個數的對象轉化成一個List集合,這個List集合時Arrays的內部類ArrayList的實例。
  • Array.ArrayList是一個固定長度的List集合,程序只能遍歷該集合裏的元素,不可增長,刪除該集合裏的元素。
public class FixedSizeLists {
    public static void main(String[] args) {
        List<String> asList = Arrays.asList(new String[]{"1","@","#","$"});
        //Exception in thread "main" java.lang.UnsupportedOperationException
        //System.out.println(asList.add("dsdsd"));
    }
}

Queue集合

  • Queue用於模擬隊列這種數據結構,隊列一般是指「先進先出FIFO」的容器。隊列的頭部保存在隊列中存放時間最長的元素,隊列的尾部保存在隊列中存放時間最短的元素。新元素插入offer到隊列的尾部,訪問元素poll操做會返回隊列頭部的元素。
  • Queue接口有一個接口Deque,Deque表明一個雙端隊列,雙端隊列能夠同時從兩端來添加元素,刪除元素,所以Deque的實現類便可當成隊列使用,也可當成棧使用。Java爲Deque提供了ArrayDeque和LinkedList兩個實現類。
public class QueueTest {
    public static void main(String[] args) {
        Queue<Integer> queue = new ArrayDeque<>();
        //將指定元素加入此隊列的尾部,當使用有容量限制的隊列時,此方法一般比add方法更好。
        queue.offer(44);
        queue.add(2);
        //[44, 2]
        System.out.println(queue);
        queue.add(3);
        //[44, 2, 3]
        System.out.println(queue);
        System.out.println(queue.poll());//44
        System.out.println(queue);//[2, 3]
        System.out.println(queue.peek());//2
        System.out.println(queue);//[2, 3]
        queue.remove();
        System.out.println(queue);//[3]
        queue.add(3434);
        System.out.println(queue);//[3, 3434]
        //返回隊列頭部元素,可是不刪除該元素
        System.out.println(queue.element());//3
        System.out.println(queue);//[3, 3434]
        System.out.println(queue.remove(3434));//true
        System.out.println(queue);//[3]
    }
}

PriorityQueue實現類 priority 優先的

  • PriorityQueue保存隊列元素的元素並非按加入隊列的順序,而是按隊列元素的大小進行從新排序,所以當調用peek方法或者poll方法去除隊列中的元素時,並非取出最早進入隊列的元素,而是取出隊列中的最小的元素。PriorityQueue已經違反了隊列的最基本的原則:先進先出
public class PriorityQueues {
    public static void main(String[] args) {
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
        priorityQueue.add(12);
        priorityQueue.add(-6);
        priorityQueue.add(-9);
        priorityQueue.add(1);
        //[-9, 1, -6, 12]
        System.out.println(priorityQueue);
        priorityQueue.poll();
        //[-6, 1, 12]
        System.out.println(priorityQueue);
    }
}
  • PriorityQueue不容許插入null元素,PriorityQueue能夠定製排序和天然排序。
  • PriorityQueue天然排序的元素必須實現Comparable接口,並且應該是同一個類的實例
  • PriorityQueue不要求隊列元素實現Comparable接口。

Deque接口和ArrayDeque實現類

  • Deque接口是Queue接口的子接口,他表明一個雙端隊列。
  • ArrayList和ArrayDeque兩個集合類的實現機制基本相同,他們的底層都是採用一個動態的可從新分配的Object[]數組來保存集合元素,當集合元素超出了該數組的容量時,系統會在底層從新分配一個Object[]數組來存儲集合元素。
  • 把ArrayDeque當成棧來使用
public class ArryDeque {
    public static void main(String[] args) {
        Deque<Integer> deque = new ArrayDeque<>();
        deque.push(1);
        deque.push(2);
        deque.push(3);
        deque.push(4);
        //[4, 3, 2, 1]
        System.out.println(deque);
        System.out.println(deque.pop()); // 4
        System.out.println(deque);//[3, 2, 1]
    }
}   //後入先出
  • 把ArrayDeque當成隊列使用
public class ArryDeque2 {
    public static void main(String[] args) {
        Deque<Integer> deque = new ArrayDeque<>();
        deque.offer(1123);
        deque.offer(143);
        deque.offer(-11);
        System.out.println(deque);//[1123, 143, -11]
        System.out.println(deque.poll());//1123
        System.out.println(deque);//[143, -11]
        System.out.println(deque.poll());//143
        System.out.println(deque);//[-11]
    }
}
  • ArrayDque不只能夠做爲棧使用,也能夠做爲隊列使用。

LinkedList實現類

  • 能夠根據索引來隨機訪問集合中的元素,LinkedList仍是實現了Deque接口,能夠被當成雙端隊列來使用,所以既能夠被當成棧使用,也能夠當作爲隊列使用。
public class LinkedListTest {
    public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<>();
        //將數組元素加入棧頂
        linkedList.push(1);
        //將數組元素加入棧底
        linkedList.offer(2);
        //[1, 2]
        System.out.println(linkedList);
        //加入棧頂
        linkedList.offerFirst(3);
        //[3, 1, 2]
        System.out.println(linkedList);
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i)); //3 1 2
        }
        //訪問但不刪除棧底
        System.out.println(linkedList.peekLast());//2
        //[3, 1, 2]
        System.out.println(linkedList);
        //訪問但不刪除棧頂
        System.out.println(linkedList.peekFirst());//3
        //[3, 1, 2]
        System.out.println(linkedList);
        //訪問並刪除棧頂
        System.out.println(linkedList.pollFirst());//3
        //[1, 2]
        System.out.println(linkedList);
    }
}
  • LinkedList和ArrayList和ArrayDeque實現機制徹底不一樣java

    • ArrayList,ArrayDeque內部以數組的形式來保存集合中的元素,所以隨機訪問幾個元素時具備較好的性能,而LinkedList內部以鏈表的形式來保存集合中的元素,所以隨機訪問集合元素時性能較差,但在插入,刪除元素時性能比較出色,只須要改變指針所指的地址便可。
    • 對於全部的內部基於數組的集合實現,例如ArrayList和ArrayDeque等,使用隨機訪問的性能比使用Iterator迭代訪問的性能要好,由於隨機訪問會被映射成對數組元素的訪問。

各類線性表的性能分析

  • Java提供的List就是一個線性表接口,而ArrayList,LinkedList又是線性表的兩種典型實現:基於數組的線性表和基於鏈的線性表。Queue表明了隊列,Deque表明了雙端隊列,既能夠做爲隊列使用,又能夠當作棧使用。
  • LinkedList集合不只提供了List的功能,還提供了雙端隊列,棧的功能。
  • 通常來講,因爲數組以一塊連續內存區來保存全部的數組元素,因此數組在隨機訪問時性能最好,全部的內部以數組做爲底層實現的集合在隨機訪問時性能都比較好。而內部以鏈表做爲底層實現的集合在執行插入,刪除操做時有較好的性能。但整體來講,ArrayList的性能比LinkedList的性能要好,所以大部分時候都應該考慮使用ArrayList。
  • 使用List集合的一些建議數組

    • 若是須要遍歷List集合,對於ArrayList,Vector集合,應該是用隨機訪問方法get來遍歷集合元素,這樣性能更好。對於LinkedList集合,則應該採用迭代器Iterator來遍歷集合元素。
    • 若是須要常常執行插入,刪除操做來改變含大量數據的List集合的大小,則可考慮使用LinkedList集合,使用ArrayList,Vector集合可能須要常常分配內部數組的大小,效果可能較差。
    • 若是有多個線程須要訪問List集合中的元素,須要考慮使用Collections將幾個包裝成線程安全集合。
相關文章
相關標籤/搜索