• java集合专题List接口ArrayList/Vector/LinkedList底层结构和源码分析


    在这里插入图片描述
    我们学习List下面ArrayList,LinkedList,Vector类即可!
    学习的重点就是了解他们的底层结构,扩容原理,通过源码进行学习!

    List接口下的一些常用方法
    在这里插入图片描述

    @SuppressWarnings("all")
    public class ArrayList_ {
        public static void main(String[] args) {
            List list = new ArrayList();
            //添加单个元素
            for (int i = 0; i <10; i++) {
                list.add(i);
            }
            //将list集合转换成数组进行打印!
            System.out.println(Arrays.toString(list.toArray()));
            //添加list集合
            List list1 = new ArrayList();
            list1.add(666);
            list1.add(888);
            //在1索引位置插入list1集合
            list.addAll(1,list1);
            //迭代器打印!
            Iterator iterator = list.iterator();
            while(iterator.hasNext()){
                System.out.print(iterator.next()+" ");
            }
            //删除元素
            list.remove(new Integer(666));
            //判断是否包含元素!
            list.contains(666);
            //删除整个list
            list.removeAll(list1);
            //返回最后一个9的下标位置!
            System.out.println("\n"+Arrays.toString(list.toArray()));
            System.out.println("从后往前找9的下标:"+list.lastIndexOf(9));
            System.out.println("6的下标:"+list.indexOf(6));
            System.out.println("拆分list集合");
            List tmp = list.subList(5,10);
            System.out.println("tmp:"+Arrays.toString(tmp.toArray()));
            //更改元素!
            System.out.println("更改前:"+list.get(0)+list.set(0,9)+"更改后:"+list.get(0));
            //排序:传入排序接口!
            System.out.println("排序前:"+Arrays.toString(list.toArray())+"\n排序后:");
            list.sort(new Comparator() {
                @Override
                public int compare(Object o1, Object o2) {
                    return (Integer) o1 - (Integer)o2;//升序
                }
            });
            //增强for遍历!
            for (Object object : list) {
                System.out.print(object+" ");
            }
    
        }
    
    }
    
    

    在这里插入图片描述

    ArrayList

    底层结构

    ArrayList底层是由数组实现的!
    在这里插入图片描述

    • ArrayList维护了一个elementData数组,由transient修饰不可序列化!

    • ArrayList扩容机制:

      • 无参构造器,默认大小为0,第一次添加元素,扩容为10,后面扩容按照1.5倍进行
      • 有参构造器,默认容量指定参数值大小,不够进行1.5倍扩容

    源码分析

    我们通过IDEA调试从而分析ArrayList底层结构和扩容机制

    无参构造器扩容机制源码分析

    我们通过下面的代码进行ArrayList无参扩容机制的分析

    public class ArrayList_ {
        public static void main(String[] args) {
            //无参扩容机制!
            ArrayList list = new ArrayList();
            //默认为 0 第一次添加扩容为 10
                for (int i = 0; i <10; i++) {
                list.add(i);
            }
            //后续扩容1.5!
            list.add(11);
        }
    }
    
    • 无参构造器初始化elementData数组长度为0
      在这里插入图片描述
    • 第一次添加
      • 装箱,因为这里的数据是int基本类,要进行装箱成Integer类!

    在这里插入图片描述
    第一次扩容
    在这里插入图片描述
    进行扩容后elementData数组长度就变成了10
    在这里插入图片描述
    当添加第11个元素时,进行二次扩容
    在这里插入图片描述

    调用int newCapacity = oldCapacity + (oldCapacity>>1); 进行1.5倍扩容!
    从而数组长度变成了15
    在这里插入图片描述

    有参构造器扩容机制源码分析

    public class ArrayList_1 {
            public static void main(String[] args) {
                //有参扩容机制,初始化指定容量大小
                ArrayList list = new ArrayList(5);
                for (int i = 0; i < 5; i++) {
                    list.add(i);
                }
                //进行第一次1.5倍扩容
                list.add(6);
            }
        }
    	
    

    在这里插入图片描述
    总结:
    每次add都会检查数组容量,是否要进行扩容!

    • 无参扩容机制

    elementData数组默认为0,当进行第一次add进行第一次扩容,扩容大小为10,而后面进行二次扩容就是1.5倍扩容!

    • 有参扩容机制

    elementData数组默认为指定参数长度,第一次扩容时,1.5倍扩容!

    Vector

    底层结构

    Vector类和ArrayList类底层的结构一样也是数组!
    不过和ArrayList区别就是,扩容策略不同,Vector是线程安全的(每个方法都加了synchronized),适用于多线程,而ArrayList线程不安全!

    扩容策略

    • 无参构造器扩容策略,初始化容量为10,后续2倍扩容
    • 有参构造器,初始化指定参数容量,后续2倍扩容
    • 可设置增量的构造器,指定初始化容量,后续扩容按增量进行

    源码分析

    在这里插入图片描述
    在这里插入图片描述
    我们学习Vector构造方法后,发现Vector有个构造器,可以设置容量的增量!
    可以自定义扩容的增量值!

    扩容机制

    通过下面的代码debug进行扩容机制的学习!

    public class Vector_ {
        public static void main(String[] args) {
            //Vector无参扩容机制!
            Vector vector = new Vector();
            //一次扩容
            for (int i = 0; i <10 ; i++) {
                vector.add(i);
            }
            //进行二次扩容
            vector.add(10);
        }
    }
    

    无参构造器,初始化容量为10
    在这里插入图片描述
    第一次扩容
    在这里插入图片描述
    有参扩容机制和无参扩容机制类似,初始化时指定数组长度!扩容策略一样!

    LinkedList

    底层结构

    LinkedList类和上述2个不同,他的底层采用的是双向链表的方式存储数据

    • LinkedList底层实现了双向链表和双端队列的特点
    • 可以添加任意元素包括null
    • 线程不安全,没有实现线程同步
    • 采用链表的方式存储,增删效率高,不需要扩容!

    在这里插入图片描述
    可以看到LinkedList实现了List接口和DeQue接口!

    在这里插入图片描述
    Node节点
    在这里插入图片描述

    这里通过frist保存头Node节点,last保存尾节点!

    因为LinkedList实现了Deque双端队列接口,所以其下的方法都实现了
    在这里插入图片描述

    方法使用

    package list;
    import java.util.Arrays;
    import java.util.LinkedList;
    public class LinkedList_ {
        public static void main(String[] args) {
            LinkedList linkedList = new LinkedList();
            linkedList.add(1);
            linkedList.addLast(2);
            linkedList.addFirst(0);
            System.out.println("获取队首元素:"+linkedList.getFirst());
            System.out.println("获取队尾元素:"+linkedList.getLast());
            System.out.println(Arrays.toString(linkedList.toArray()));
            System.out.println("出队:"+linkedList.poll());
            System.out.println(Arrays.toString(linkedList.toArray()));
            System.out.println("对尾删除元素:"+linkedList.pollLast());
            linkedList.push(12);
            linkedList.pop();
            System.out.println(Arrays.toString(linkedList.toArray()));
        }
    }
    
    

    在这里插入图片描述
    注意:

    这里的方法有点多:offer/poll push/pop add/remove
    这里只有push/pop不能进行First/Last组合,其他都可!

    源码分析

     public static void main(String[] args) {
            LinkedList<Integer> list = new LinkedList<>();
            list.add(1);
            list.remove();
            list.get(1);
        }
    

    add添加节点

    默认队尾入队

    在这里插入图片描述
    remove删除节点

    默认删除第一个节点!

    在这里插入图片描述
    get方法获取节点

    在这里插入图片描述

    三者比较

    底层结构增删效率改查效率
    ArrayList/Vector可变数组较低,要扩容较高
    LinkedList双向链表较高,通过链表修改指针即可较低

    三者如何抉择:

    • 如果改查操作多且单线程使用ArrayList,如果多线程就vector!
    • 如果增删操作多,那就LinkedList
    • 一般来说查询基本上查询为主,所以首选ArrayList!
  • 相关阅读:
    苹果AirTag成为作案工具?偷车贼用其追踪高端汽车
    ElasticSearch 一文读懂
    测试开发【Mock平台】10基础:拦截器实现Mock功能(一)探索HandlerInterceptor
    用Python造轮子
    飞行动力学 - 第17节-part3-垂尾和推进系统对航向的影响 之 基础点摘要
    【Python】绘制 对数函数
    IP 子网划分工具
    常用的三角函数公式
    Java 多态
    【Linux】 - Linux中的重定向和管道符
  • 原文地址:https://blog.csdn.net/weixin_52345071/article/details/126852667