zoukankan      html  css  js  c++  java
  • 集合:List接口的实现类(ArrayList、LinkedList、Vector)

    1、List接口

    (1)特点

    • 有序(插入和取出的顺序相等,因为有一个整数索引记录了元素的插入的位置)
    • 允许有重复的元素(调用equals方法返回true,允许有多个null)
        @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(null);
                 list.add(111);
                 list.add(null);
                 System.out.println(list);
        }
    [123, 123, null, 111, null]

    (2)与collection相比的特有方法

    • add(index,元素):在指定的位置插入
    • get(index):获取指定位置的元素
    • remove(index):删除指定位置的元素
    • set(index,新元素):修改指定位置的元素
    • subList(index,index):根据索引范围截取一个子集合
    • indexOf(元素):查找

    与collection接口的最大区别就是list接口的操作会涉及到索引。

    2、List接口的特有方法

    (1)增加元素

    指定位置插入

        @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(null);
                 list.add(111);
                 list.add(null);
                 list.add(1,"zhai");
                 System.out.println(list);
        }
    [123, zhai, 123, null, 111, null]

    (2)下标越界异常

        @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add(1,"zhai");
                 System.out.println(list);
        }
    java.lang.IndexOutOfBoundsException: Index: 1, Size: 0

    程序源码:

    判断索引的范围是否有效:

     索引大于集合大小或索引小于0,抛出异常:

     (2)删除元素

    根据索引删除:

    @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(null);
                 list.add(111);
                 list.add(null);
                 list.remove(2);
                 System.out.println(list);
        }
    [123, 123, 111, null]

    默认按照索引删除:

    @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(8848);
                 list.add(111);
                 list.add(1);
                 list.remove(1);
                 System.out.println(list);
        }
    [123, 8848, 111, 1]

    在可以按照索引删除和按照元素删除的情况下,List默认按照索引删除元素

     编译器提示的也是按照索引删除,因为不存在100索引,会抛出异常:

    java.lang.IndexOutOfBoundsException: Index: 100, Size: 5

     查看源码可以看出remove存在方法的重载,index是基本数据类型的数据,如果是按照内容移除还要讲int类型转换为Integer类型,显然是不合理的

     @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(8848);
                 list.add(111);
                 list.add(100);
                 list.remove(new Integer(100));
                 System.out.println(list);
        }
    [123, 123, 8848, 111]

    直接传递引用类型的数据,不会再调用参数列表为int类型的remove方法,而是直接调用按照内容移除元素的方法

    总结:

    如果元素的类型为int的,默认按照索引删除;如果想要按照指定的元素删除,则需要装箱后再删除

    (3)修改

    (1)修改指定位置的元素:

    @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(8848);
                 list.add(111);
                 list.add(100);
                 list.set(1,"2020年8月5日08:41:50");
                 System.out.println(list);
        }
    [123, 2020年8月5日08:41:50, 8848, 111, 100]

    (4)查找

    @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(8848);
                 list.add(111);
                 list.add(100);
                 System.out.println(list.indexOf(100));
        }
    4

    3、list接口的遍历方式

    (1)迭代器

      @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(8848);
                 list.add(111);
                 list.add(100);
            Iterator iterator=list.iterator();
            while (iterator.hasNext()){
                Object l=iterator.next();
                System.out.println(l);
            }
        }
    123
    123
    8848
    111
    100

    (2)增强for

     @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(8848);
                 list.add(111);
                 list.add(100);
                 for (Object l:list){
                     System.out.println(l);
                 }
        }
    123
    123
    8848
    111
    100

    (3)普通for

    @Test
        public void test1() {
                 List list=new ArrayList();
                 list.add("123");
                 list.add("123");
                 list.add(8848);
                 list.add(111);
                 list.add(100);
                 for (int i=0;i<list.size();i++){
                     System.out.println(list.get(i));
                 }
    
        }
    123
    123
    8848
    111
    100

    因为list接口可以操作索引,因此,可以采用for循环遍历list接口的数据

    4、ArrayList源码分析与底层结构

    (1)可变长度的实现

    代码:

    @Test
        public void test1() {
                 ArrayList list=new ArrayList();
                 for (int i=0;i<=10;i++){
                     list.add("join"+i);
                 }
                    for (int i=11;i<=20;i++){
                        list.add("join"+i);
                    }
                    System.out.println(list);
        }

    运行至集合中有10个元素:

     底层实际上是可变数组,该数组是Object类型的,初始的时候数组的长度为0,第一次扩容为10,第二次为15,第三次增加为22... ... 也就是说数组的长度以1.5倍的速度增加

    源码分析:

     因为该变量是一个长度为0的数组:

     add方法:

     

     数组的扩容:

     elementData是存储集合的可变数组:

    5、Vector底层与ArrayList的对比

    (1)相同点

    底层都是可变数组

    (2)不同点

    版本:

    • ArrayList:新
    • Vector:旧

    线程安全:

    • ArrayList:线程不安全,效率高
    • Vector:线程安全(同步),效率低

    扩容倍数:

    • Vector变为原来的2倍

    •  Arraylist:变为原来的1.5倍

    6、LinkedList底层和源码分析

    (1)LinkedList

    底层是双向链表

    • 每个结点维护三个属性:item代表自己,next代表下一个元素,prev代表前一个元素
    • LinkedList维护两个重要属性:first和last,分别指向首结点和尾结点

    (2)源码分析

     构造器为空:

      public LinkedList() {
        }

    添加元素的源码分析:

       public boolean add(E e) {
            linkLast(e);
            return true;
        }
    void linkLast(E e) {
            final Node<E> l = last;
            final Node<E> newNode = new Node<>(l, e, null);
            last = newNode;
            if (l == null)
                first = newNode;
            else
                l.next = newNode;
            size++;
            modCount++;
        }

    new Node<>(l, e, null):三个参数分别是:前一个、当前元素、下一个

    尾插法添加元素,第一次添加first就是第一个元素,不为空的时候在last后添加

    (3)与ArrayList的对比

    底层结构

    ArrayList:可变数组

    LinkedList:双向链表

    增删的效率

    ArrayList:需要移动大量的元素效率较低

    LinkedList:插入时不需要移动内存中的元素,只需要改变引用的指向即可,所以插入或删除的效率高

    改查的效率

    ArrayList:具有索引,查询或修改快

    LinkedList:查询时从头部开始,一个一个地找,查询效率较低(虽然有索引,但是查询方式不同,LInkedList必须一个一个查询,而ArrayList可以直接获取相应索引的元素)

    使用场景

    ArrayList:使用在查询比较多,插入删除较少的情况

    LinkedList:使用在查询比较少,插入和删除比较多的情况

    总结:

    1、List的接口的三个实现类的选择

    如果考虑线程安全的问题,采用Vector

    不考虑线程安全的问题的话,如果查询较多用ArrayList,增删较多用LinkedList

  • 相关阅读:
    PAT 1005. 继续(3n+1)猜想 (25)
    PAT 1004. 成绩排名 (20)
    android小游戏 飞机躲子弹
    PAT 1004. 成绩排名 (20) JAVA
    PAT 1003. 我要通过!(20) JAVA
    PAT 1003. 我要通过!(20)
    PAT 1002. 写出这个数 (20)
    NEERC, Northern Subregional Contest 2012 B 乱搞or搜索
    SGU 167 未解 dp
    Bucharest, Romania 2013 A Russian Dolls 贪心
  • 原文地址:https://www.cnblogs.com/zhai1997/p/13438829.html
Copyright © 2011-2022 走看看