面试相关-List总结

本文深入探讨Java中List的三种实现:ArrayList, LinkedList和Vector。详细分析了它们的内部结构、性能特点及适用场景,帮助读者理解如何根据需求选择最适合的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package Other;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Vector;

/**
 * @author vincent
 * @description 面试相关List
 * @Date 2020-03-18 17:03
 */
public class LList {

    public static void main(String[] args) {
        /**
         * ArrayList
         */
        ArrayList<Object> arrayList = new ArrayList<>();
        // 结构是数组 object[]
        // 优点查找和访问速度更快 缺点新增删除慢线程不安全
        // 延伸: 插入速度快但是查找速度慢的是linkedlist 线程安全的是vector

        ArrayList<Object> objects = new ArrayList<>(10);
        ArrayList<Object> objects2 = new ArrayList<>(10);
        // 因为结构是数组,所以构造方法可以传入初始长度 默认是0
        // Java经典bug 构造方法赋初始长度,只是构建了一个长度的数组,但是size还是0
        // 如果此时set,会报越界错误 除非初始后就add够足够的长度
        for (int i = 0; i < 10000; i++) {
            objects.add(i);
            objects2.add(i);
        }
//        objects.add(5,"5");


        arrayList.add("");
        // 空数组,只有第一次add操作才会赋值10的初始长度
        // 数组扩容公式
        // int newCapacity = oldCapacity + (oldCapacity >> 1); oldCapacity为当前数组长度 翻译:len+len/2
        // 扩容方式和hashmap一样,都是新建一个数组 复制
        // 10这个默认值,在Java里都是sun公司根据调研,得出的大概最有效率的一个初值

        //新增删除效率问题
        arrayList.add(null);// 普通新增不指定index则直接加在数组最后
//        arrayList.add(5,null);
        // 如果指定位置的话
        // 看源代码可以看到,首先判断数组是否需要扩容,其次index+1后的所有数组进行copy,然后再把新增元素添加到index位置
        // 如果数组长度够大,len-index-1的元素复制太多,效率可想而知
        arrayList.remove(null); // 删除同理,先for循环对比得到index,len-index-1的元素向前复制,置len位置为null

        // 新增删除就一点慢吗
        // 答案是否定的,我们通过源码可以看到,arraylist主要是通过复制截取数组来实现的插入和删除,并不涉及移位,这里就考量到一个index,即操作的元素在数组中的位置
        long startTime=System.nanoTime();
        objects.remove(5000);
        long endTime=System.nanoTime();
        System.out.println("删除1000运行时间: "+(endTime - startTime)+"ms");
        long endTime2=System.nanoTime();
        objects2.remove(9000);
        System.out.println("删除9000运行时间: "+(endTime2 - endTime)+"ms");
        // 通过上面这段代码,我们能看出,index越靠近尾部,执行效率越低

        //arraylist适合用来做队列吗
        // 我们首先了解队列的原则应该是先入先出first in first out
        // 即我们的remove要remove头,add要add尾,反过来也可以
        // 我们知道arrayList的新增删除都需要复制移位,效率低,所以不适合
        // 相反,数组是适合做队列的,经典的几个队列底层都是使用的定长环形队列

        /**
         * LinkedList
         */
        LinkedList<Object> linkedList = new LinkedList<>();
        // 结构链表
        linkedList.add(null); // 插入因为只需要操作尾部的next即可,所以效率高
        linkedList.add(1,null); // 先定位index,元素的next链接index的next,元素的pre链接index,index的next指向元素
        linkedList.get(1); // 这里看源码可以看到,判断index和size/2,决定是在链表前半段查找,还是后半段查找
        linkedList.indexOf(null);// indexof都是从头判断到尾

        // 所有源码有modcount的都是failfast机制(快速失败),即遍历时,如果其他线程操作该元素导致该元素的modcount改变,则此次遍历会报错

        /**
         * 对比
         */
        // arrayList因为底层结构是数组,数组是一片连续的空间,读取都很快,但是插入删除需要频繁的开辟新的数组复制
        // linkedList因为底层结构是链表,链表没有扩容问题,有新数据就建一个node,改变前驱后驱即可,但是因为数据在内存中存储空间不连续,读取效率低


        /**
         * 线程安全的Vector
         */
        Vector<Object> vector = new Vector<>();
        // vector的源码其实和arrayList一模一样,只是每个方法上加了synchronized保证线程安全
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值