java中arraylist面试题_Java中ArrayList相关的5道面试题

本文详细解析了Java中ArrayList的五个面试重点:1) ArrayList如何自动扩容;2) 使用ArrayList与LinkedList的选择场景;3) 安全隐患及解决办法;4) ArrayList的复制方法;5) 插入删除操作的效率问题。通过源码分析,帮助理解ArrayList的内部机制和优化策略。
摘要由CSDN通过智能技术生成

1、ArrayList的大小是如何自动增加的?

这个问题我想曾经debug过并且查看过arraylist源码的人都有印象,它的过程是:当试图在一个arraylist中增加一个对象时,Java会去检查arraylist,确保已存在的数组中有足够的容量(默认是10),如果没有足够的容量,那么就会新建一个长度更长(是原来数组长度的1.5倍)的数组,旧的数组就会使用Arrays.copyOf()方法被复制到新的数组中。

来看源代码:

/*** Appends the specified element to the end of this list.

*

*@parame element to be appended to this list

*@returntrue (as specified by {@linkCollection#add})*/

public booleanadd(E e) {

ensureCapacity(size+ 1); //Increments modCount!!

elementData[size++] =e;return true;

}/*** Increases the capacity of this ArrayList instance, if

* necessary, to ensure that it can hold at least the number of elements

* specified by the minimum capacity argument.

*

*@paramminCapacity the desired minimum capacity*/

public void ensureCapacity(intminCapacity) {

modCount++;int oldCapacity =elementData.length;if (minCapacity >oldCapacity) {

Object oldData[]=elementData;int newCapacity = (oldCapacity * 3)/2 + 1;if (newCapacity

newCapacity=minCapacity;//minCapacity is usually close to size, so this is a win:

elementData =Arrays.copyOf(elementData, newCapacity);

}

}

2、什么情况下使用ArrayList,什么情况下使用LinkedList?

首先来看LinkedList是什么:

private transient Entry header = new Entry(null, null, null);private transient int size = 0;/*** Constructs an empty list.*/

publicLinkedList() {

header.next= header.previous =header;

}

没错,它就是一个链表,每一个节点都是Entry,而ArrayList是一个数组,初始化的大小是10:

public ArrayList(intinitialCapacity) {super();if (initialCapacity < 0)throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);this.elementData = newObject[initialCapacity];

}/*** Constructs an empty list with an initial capacity of ten.*/

publicArrayList() {this(10);

}

好,搞清楚这个之后,我们可以知道:①、对于数组的访问,即使是最糟糕的情况下,时间复杂度也是O(1),而对于链表来说,最糟糕的情况下,时间复杂度是O(N)。②、对于数组来说,当旧容量无法容下新增对象时,会将就的数组复制到一个新的数组里面,这里需要消耗时间,也就是说增加一个对象可能会耗时比较久,而对于链表来说,新增一个对象只是初始化一个entry,然后将其插入到链表表尾,耗时并不会太长。

看LinkedList的add方法:

public booleanadd(E e) {

addBefore(e, header);return true;

}private Entry addBefore(E e, Entryentry) {

Entry newEntry = new Entry(e, entry, entry.previous);

newEntry.previous.next=newEntry;

newEntry.next.previous=newEntry;

size++;

modCount++;returnnewEntry;

}

所以,引用原文的话:多数情况下,当你遇到访问元素比插入或者是删除元素更加频繁的时候,你应该使用ArrayList。另外一方面,当你在某个特别的索引中,插入或者是删除元素更加频繁,或者你压根就不需要访问元素的时候,你会选择LinkedList。

3、当传递一个ArrayList到某个方法,或者某个方法返回ArrayList,什么时候要考虑安全隐患?如何修复这个安全违规问题?

当array被当做参数传递到某个方法中,如果array在没有被复制的情况下直接被分配给了成员变量,那么就可能发生这种情况,即当原始的数组被调用的方法改变的时候,传递到这个方法中的数组也会改变。

来看例子:

public classArray {

String []myArray={};public voidSetMyArray(String []myArray){this.myArray = myArray;//这里有安全隐患

}publicString[] getMyArray(){return this.myArray;//这里有安全隐患

}public static voidmain(String []args){

Array a= newArray();

String b[]= {"i "," am ","from ","china"};

a.SetMyArray(b);

System.out.println(a.getMyArray()[0]);

b[0]="you";

System.out.println(a.getMyArray()[0]);

}

}

输出结果:

i

you

很明显,我们只修改了b[0],但是却影响到a[0](假设我们的目的是修改b并不会影响a),既然出现这个问题,那么我们对set方法做一次改进:

public void SetMyArray(String []myArray){//修改后的set方法

if(myArray == null){this.myArray = new String[0];

}else{this.myArray =Arrays.copyOf(myArray, myArray.length);

}

}

此时的运行结果:

i

i

所以此时的b和a都是分开的,互不影响的。

4、如何复制某个ArrayList到另一个Arraylist中去?用原文的话来说:

使用clone()方法,比如ArrayList newArray = oldArray.clone();

使用ArrayList构造方法,比如:ArrayList myObject = new ArrayList(myTempObject);

使用Collection的copy方法。

注意1和2是浅拷贝(shallow copy)。

关于浅拷贝,深拷贝,参考这篇文章。

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

在ArrayList中增加或者是删除元素,要调用System.arraycopy这种效率很低的操作,如果遇到了需要频繁插入或者是删除的时候,你可以选择其他的Java集合,比如LinkedList。看一下下面的代码:

在某个索引处增加一个元素:

1 public void add(intindex, E element) {2 if (index > size || index < 0)3 throw newIndexOutOfBoundsException(4 "Index: "+index+", Size: "+size);5

6 ensureCapacity(size+1); //Increments modCount!!

7 System.arraycopy(elementData, index, elementData, index + 1,8 size -index);9 elementData[index] =element;10 size++;11 }

在某个索引处删除某个元素:

1 public E remove(intindex) {2 RangeCheck(index);3

4 modCount++;5 E oldValue =(E) elementData[index];6

7 int numMoved = size - index - 1;8 if (numMoved > 0)9 System.arraycopy(elementData, index+1, elementData, index,10 numMoved);11 elementData[--size] = null; //Let gc do its work

12

13 returnoldValue;14 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值