ArrayList常见和不常见面试题

ArrayList插入删除一定慢么?

 取决于你删除的元素离数组末端有多远,ArrayList拿来作为堆栈来用还是挺合适的,push和pop操作完全不涉及数据移动操作。

ArrayList的遍历和LinkedList遍历性能比较如何?

 论遍历ArrayList要比LinkedList快得多,ArrayList遍历最大的优势在于内存的连续性,CPU的内部缓存结构会缓存连续的内存片段,可以大幅降低读取内存的性能开销。

ArrayList是如何扩容的?

 ArrayList扩容后的大小等于扩容前大小的1.5倍,当ArrayList很大的时候,这样扩容还是挺浪费空间的,甚至会导致内存不足抛出OutOfMemoryError。扩容的时候还需要对数组进行拷贝,这个也挺费时的。所以我们使用的时候要竭力避免扩容,提供一个初始估计容量参数,以免扩容对性能带来较大影响。

ArrayList的默认容量大小?

 在Java1.8中,如果new ArrayList(),则默认的容量是0,在第一次添加数据时会设置默认的容量为10。后续扩容是会增长到原来的1.5倍,如果增长后长度大于MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8),则最大长度为Integer.MAX_VALUE。

ArrayList 的默认数组大小为什么是10?

 据说是因为sun的程序员对一系列广泛使用的程序代码进行了调研,结果就是10这个长度的数组是最常用的最有效率的。也有说就是随便起的一个数字,8个12个都没什么区别,只是因为10这个数组比较的圆满而已。

在索引中ArrayList的增加或者删除某个对象的运行过程?效率很低吗?解释一下为什么?

 效率是很低的,因为ArrayList无论是增加或者删除某个对象,我们都要通过对数组中的元素进行移位来实现。

 增加元素时,我们要把要增加位置及以后的所有元素都往后移一位,先腾出一个空间,然后再进行添加。
 删除某个元素时,我们也要把删除位置以后的元素全部元素往前挪一位,通过覆盖的方式来删除。
 而这种移位就需要不断的arraycopy,是很耗时间的,所以效率自然也很低。

ArrayList的subList方法

 这个方法返回一个SubList对象,这个List是ArrayList的一个内部类,这个类和ArrayList公用数据对象,对SubList的操作最终会反应到原List中。

Arrays.asList创建ArrayList有什么问题?

 我们用Arrays生成一个ArrayList,然后添加其他数据,结果程序抛出一个异常UnsupportedOperationException。

 抛出异常的原因为,Arrays创建的ArrayList和java.util.ArrayList并非是同一个,用Arrays创建的ArrayList是Arrays的一个内部类,这个内部类并没有实现add方法导致的。

ArrayList 做队列合适么?
 队列一般是FIFO的,如果用ArrayList做队列,就需要在数组尾部追加数据,数组头部删除数组,反过来也可以。但是无论如何总会有一个操作会涉及到数组的数据搬迁,这个是比较耗费性能的。

 这个回答是错误的!

 ArrayList固然不适合做队列,但是数组是非常合适的。比如ArrayBlockingQueue内部实现就是一个环形队列,它是一个定长队列,内部是用一个定长数组来实现的。另外著名的Disruptor开源Library也是用环形数组来实现的超高性能队列,具体原理不做解释,比较复杂。简单点说就是使用两个偏移量来标记数组的读位置和写位置,如果超过长度就折回到数组开头,前提是它们是定长数组。

ArrayList 中的 elementData 为什么是 Object 而不是泛型 E ?

 Java 中泛型运用的目的就是实现对象的重用,泛型T和Object类其实在编写时没有太大区别,只是JVM中没有T这个概念,T只是存在于编写时,进入虚拟机运行时,虚拟机会对泛型标志进行擦除,也就是替换T会限定类型替换(根据运行时类型),如果没有限定就会用Object替换。同时Object可以new Object(),就是说可以实例化,而T则不能实例化。在反射方面来说,从运行时,返回一个T的实例时,不需要经过强制转换,然后Object则需要经过转换才能得到。

ArrayList list = new ArrayList(20); 中的list扩充几次?

 默认ArrayList的长度是10个,所以如果你要往list里添加20个元素肯定要扩充一次(newCapacity 扩充为原来的1.5倍,但和输入的minCapacity相比发现小于minCapacity,于是 newCapacity = minCapacity,所以只扩容一次,具体见扩容里的grow方法),但是这里显示指明了需要多少空间,所以就一次性为你分配这么多空间,也就是不需要扩充了!

ArrayList 底层实现就是数组,访问速度本身就很快,为何还要实现 RandomAccess ?
 RandomAccess是一个空的接口, 空接口一般只是作为一个标识, 如Serializable接口. JDK文档说明RandomAccess是一个标记接口(Marker interface), 被用于List接口的实现类, 表明这个实现类支持快速随机访问功能(如ArrayList). 当程序在遍历这中List的实现类时, 可以根据这个标识来选择更高效的遍历方式。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值