大厂面试 | 别再问我Java List八股文了!

简介: 根据校招大厂面试经历进行整理,以微信聊天的方式模拟面试现场,生动有趣的讲解八股文~

面试官:你好,我是面试官xxx,请问你是大彬吗?

大彬:面试官,您好,我是大彬

面试官:现在方便面试吗?

大彬:嗯嗯,可以的

面试官:那我们现在开始面试吧

面试官看你简历上写了熟悉集合相关内容,你了解Java的List吗?

大彬:嗯,List是一个接口,常见的实现类有ArrayList和LinkedList

面试官讲讲这两个实现类的区别?

独白:老八股文了哈哈

大彬:ArrayList的底层数据结构是数组,支持下标访问,查询数据快。默认初始值大小为10,容量不足时会进行扩容

大彬:而LinkedList的底层数据结构是链表,将元素添加到链表的末尾,无需扩容

面试官嗯嗯,刚刚你提到ArrayList的扩容,详细讲讲?

独白:好家伙,就知道你会问这个,八股文都已经准备好了。

大彬:ArrayList扩容源码实现如下:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  //扩容
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

大彬:可以看到,在grow方法里面进行扩容,将数组容量扩大为原来的1.5倍。

大彬:举个例子,如果初始化的值是8,当添加第9个元素的时候,发现数组空间不够,就会进行扩容,扩容之后容量为12。

大彬:扩容之后,会调用Arrays.copyOf()方法对数组进行拷贝。

面试官嗯,不错,那ArrayList和LinkedList分别适用于什么场景?

大彬:对于随机index访问的get和set方法,ArrayList的速度要优于LinkedList。因为ArrayList直接通过数组下标直接找到元素;LinkedList要移动指针遍历每个元素直到找到为止。

大彬:新增和删除元素,LinkedList的速度要优于ArrayList。因为ArrayList在新增和删除元素时,可能扩容和复制数组;而LinkedList的新增和删除操作只需要修改指针即可。

大彬:因此,ArrayList适用于查询多,增删少的场景。而LinkedList适用于查询少,增删多的场景

面试官讲讲Set和List的区别?

大彬:List 以索引来存取元素,有序的,元素是允许重复的,可以插入多个null;Set 不能存放重复元素,无序的,只允许插入一个null。

大彬:List 底层实现有数组、链表两种方式;Set 基于 Map 实现,Set 里的元素值就是 Map的键值。

面试官了解Vector吗?

大彬:嗯,Vector是底层结构是数组,现在基本没有使用Vector了,因为操作Vector效率比较低。相对于ArrayList,它是线程安全的,在扩容的时候容量扩展为原来的2倍。

面试官嗯,那你还知道有哪些线程安全的List吗?

大彬:可以使用Collections.synchronizedList()方法返回一个线程安全的List。

大彬:还有另一种方式,使用CopyOnWriteArrayList。

面试官嗯哼,刚刚你提到CopyOnWriteArrayList,详细讲讲它的原理?

独白:这也太卷了吧,一言不合就是底层原理...

大彬:CopyOnWriteArrayList是一个线程安全的List,底层是通过复制数组的方式来实现的。

大彬:所谓的CopyOnWrite,就是写时复制。

大彬:当我们往容器添加元素时,不直接往容器添加,而是先将当前容器进行复制,复制出一个新的容器,然后往新的容器添加元素,添加完元素之后,再将原容器的引用指向新容器。

大彬:这样做的好处就是可以对CopyOnWrite容器进行并发的读而不需要加锁,因为当前容器不会被修改。

public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock(); //add方法需要加锁
    try {
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1); //复制新数组
        newElements[len] = e;
        setArray(newElements); //原容器的引用指向新容器
        return true;
    } finally {
        lock.unlock();
    }
}

面试官那你能说说CopyOnWriteArrayList有什么缺点吗?

大彬:主要有以下两个问题。

大彬:内存占用问题。由于CopyOnWrite的写时复制机制,在进行写操作的时候,内存里会同时驻扎两个对象的内存。

大彬:CopyOnWrite容器不能保证数据的实时一致性,可能读取到旧数据。

面试官:嗯,可以。

面试官问一些平时开发经常遇到的问题,怎么给List排序呢?

大彬:可以使用list自身的sort方法,或者使用Collections.sort(list)方法。

面试官怎么在遍历 ArrayList 时移除一个元素?

大彬:如果使用foreach删除元素的话,会导致快速失败(fast-fail)问题,可以使用迭代器的 remove() 方法,避免fast-fail问题。

Iterator itr = list.iterator();
while(itr.hasNext()) {
      if(itr.next().equals("dabin") {
        itr.remove();
      }
}

面试官:基础还不错!回去等通知

大彬:好的,谢谢你

独白:回去等通知?不会凉了吧...

相关文章
|
21天前
|
缓存 Java 关系型数据库
【Java面试题汇总】ElasticSearch篇(2023版)
倒排索引、MySQL和ES一致性、ES近实时、ES集群的节点、分片、搭建、脑裂、调优。
【Java面试题汇总】ElasticSearch篇(2023版)
|
21天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
175 37
|
21天前
|
设计模式 安全 算法
【Java面试题汇总】设计模式篇(2023版)
谈谈你对设计模式的理解、七大原则、单例模式、工厂模式、代理模式、模板模式、观察者模式、JDK中用到的设计模式、Spring中用到的设计模式
【Java面试题汇总】设计模式篇(2023版)
|
21天前
|
存储 关系型数据库 MySQL
【Java面试题汇总】MySQL数据库篇(2023版)
聚簇索引和非聚簇索引、索引的底层数据结构、B树和B+树、MySQL为什么不用红黑树而用B+树、数据库引擎有哪些、InnoDB的MVCC、乐观锁和悲观锁、ACID、事务隔离级别、MySQL主从同步、MySQL调优
【Java面试题汇总】MySQL数据库篇(2023版)
|
21天前
|
存储 缓存 NoSQL
【Java面试题汇总】Redis篇(2023版)
Redis的数据类型、zset底层实现、持久化策略、分布式锁、缓存穿透、击穿、雪崩的区别、双写一致性、主从同步机制、单线程架构、高可用、缓存淘汰策略、Redis事务是否满足ACID、如何排查Redis中的慢查询
【Java面试题汇总】Redis篇(2023版)
|
21天前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
21天前
|
缓存 Java 数据库
【Java面试题汇总】Spring篇(2023版)
IoC、DI、aop、事务、为什么不建议@Transactional、事务传播级别、@Autowired和@Resource注解的区别、BeanFactory和FactoryBean的区别、Bean的作用域,以及默认的作用域、Bean的生命周期、循环依赖、三级缓存、
【Java面试题汇总】Spring篇(2023版)
|
21天前
|
存储 缓存 监控
【Java面试题汇总】JVM篇(2023版)
JVM内存模型、双亲委派模型、类加载机制、内存溢出、垃圾回收机制、内存泄漏、垃圾回收流程、垃圾回收器、G1、CMS、JVM调优
【Java面试题汇总】JVM篇(2023版)
|
21天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
10天前
|
消息中间件 NoSQL Java
Java知识要点及面试题
该文档涵盖Java后端开发的关键知识点,包括Java基础、JVM、多线程、MySQL、Redis、Spring框架、Spring Cloud、Kafka及分布式系统设计。针对每个主题,文档列举了重要概念及面试常问问题,帮助读者全面掌握相关技术并准备面试。例如,Java基础部分涉及面向对象编程、数据类型、异常处理等;JVM部分则讲解内存结构、类加载机制及垃圾回收算法。此外,还介绍了多线程的生命周期、同步机制及线程池使用,数据库设计与优化,以及分布式系统中的微服务、RPC调用和负载均衡等。
下一篇
无影云桌面