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将几个包装成线程安全集合。
相关文章
相关标签/搜索