关于List的一些问题

1 扩容类问题

1. ArrayList无参构造器构造,现在add一个值进去,此时数组的大小是多少,下一次扩容前最大可用大小是多少?
答:此时数组的大小是1,下一次最大可用大小是10,因为ArrayList第一次扩容时是有默认值的,默认值是10,在第一次add一个值进去时,数组的可用大小被扩容到10了。
2. 如果连续往list里面add值,增加到11个的时候,数组最大可用大小是多少?
答: 因为ArrayList第一次扩容的最大容量是10,所以add到11个的时候,ArrayList第二次及其以后的扩容规则是原来容量的1.5倍,所以数组最大可用大小是15。
3. 数据初始化,被加入一个值后,如果使用addAll()方法,一下子加入15个值,最终的数组的大小是多少?
答:16,因为加入1个值后,数组容量为10,又加入15个值,那么我们期望的值为16,可是按照扩容规则,一次扩容的大小是原来的1.5倍,即扩容后的数组容量是15,是小于16的。所以,源码中有一种策略:

// 如果此次扩容的大小newCapacity 小于我们此次期望的大小minCapacity ,那么数组容量就等于期望的大小
if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;

4. 现在有一个很大的数组需要拷贝,原数组大小是5K,请问如何快速拷贝?
答:因为数组比较大,如果新建新数组的时候,不指定数组大小的话,就会频繁扩容,造成拷贝的性能低下,可以在新建数组的时候指定数组大小为5K。
5. 为什么说扩容会消耗性能?
答:扩容底层使用的是System.arraycopy方法,会把原数组的数据全部拷贝到新数组上,所以性能损耗严重。

2 删除类问题

1. 有一个ArrayList,数据时1、3、3、3、4,中间有三个3,现在通过for循环的方式,想把值为3的元素删除,请问可以删除干净吗?最后的结果是什么?

public class Test {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		ArrayList<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(3);
		list.add(3);
		list.add(3);
		list.add(4);
		for (int i = 0; i < list.size(); i++) {
    
    
			if (list.get(i).equals(3)) {
    
    
				list.remove(i);
			}
			
		}
		for (Integer integer : list) {
    
    
			System.out.println(integer);
		}
		
	}

}

答:结果是1、3、4,因为每次循环如果删除了其中一个3,那么当前这个3后面的值会全部向前移动一位,此时循环不断增加,其中就会漏掉一个3。
2. 还是上面的数组,如果通过增强for循环进行删除,可以吗?
答: 不可以,会报错。因为增强for循环实际上就是调用迭代器的next()方法,当你调用list.remove()方法进行删除时,modCount的值会+1,而这个时候迭代器中的expectedModCount的值却没有变,导致迭代器下次执行next()方法时,expectedModCount!=modCount会报错。
3. 还是上面的数组,如果通过iterator.remove()方法可以删除吗?
答:可以的,因为iterator.remove()方法在执行过程中,会把最新的modCount赋值给expectedModCount,两者会相等。

3. 对比类问题

1. ArrayList和LinkedList有何不同?
答:两者的底层数据结构不同,前者是数组,后者是双向链表。两者数据结构的不同也导致了操作的API实现不同,比如新增操作,ArrayList会先计算是否扩容,然后把把新增的数据直接赋值到数组上,而LinkedList仅仅只需要改变插入节点和其前后的指向。
2. ArrayList和LinkedList应用场景有何不同?
答: ArrayList更适合查多写少,LinkedList反之。
3. ArrayList和LinkedList两者有没有最大容量?
答:ArrayList有最大容量,为Integer.MAX_VALUE,大于这个值JVM不会为数组分配内存空间的;LinkedList底层是双向链表,理论上可以无限大,但LinkedList实际大小用的是int类型,说明LinkedList也不能超过Integer的最大值。
4. ArrayList和LinkedList如何对null值处理的?
答:ArrayList和LinkedList都允许null值新增,也允许null值删除。
5. ArrayList和LinkedList是线程安全的吗?
答:当两着作为非共享变量时,比如方法中的局部变量时,是没有线程安全问题的,只有当两者作为共享变量时,才会有线程安全问题。在多线程下,变量会存在原子性和可见性问题,对数组或链表进行操作会导致值被覆盖的情况。可以使用Collections.synchronizedList解决或者用CopyOnWriteArrayList 解决。

猜你喜欢

转载自blog.csdn.net/qq_36986015/article/details/107846128