本文参考了 《关于ArrayList的5道面试题 》

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

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

来看源代码:

  1. /**
  2. * Appends the specified element to the end of this list.
  3. *
  4. * @param e element to be appended to this list
  5. * @return <tt>true</tt> (as specified by {@link Collection#add})
  6. */
  7. public boolean add(E e) {
  8. ensureCapacity(size + 1); // Increments modCount!!
  9. elementData[size++] = e;
  10. return true;
  11. }
  12.  
  13. /**
  14. * Increases the capacity of this <tt>ArrayList</tt> instance, if
  15. * necessary, to ensure that it can hold at least the number of elements
  16. * specified by the minimum capacity argument.
  17. *
  18. * @param minCapacity the desired minimum capacity
  19. */
  20. public void ensureCapacity(int minCapacity) {
  21. modCount++;
  22. int oldCapacity = elementData.length;
  23. if (minCapacity > oldCapacity) {
  24. Object oldData[] = elementData;
  25. int newCapacity = (oldCapacity * 3)/2 + 1;
  26. if (newCapacity < minCapacity)
  27. newCapacity = minCapacity;
  28. // minCapacity is usually close to size, so this is a win:
  29. elementData = Arrays.copyOf(elementData, newCapacity);
  30. }
  31. }

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

首先来看LinkedList是什么:

  1. private transient Entry<E> header = new Entry<E>(null, null, null);
  2. private transient int size = 0;
  3.  
  4. /**
  5. * Constructs an empty list.
  6. */
  7. public LinkedList() {
  8. header.next = header.previous = header;
  9. }

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

  1. public ArrayList(int initialCapacity) {
  2. super();
  3. if (initialCapacity < 0)
  4. throw new IllegalArgumentException("Illegal Capacity: "+
  5. initialCapacity);
  6. this.elementData = new Object[initialCapacity];
  7. }
  8.  
  9. /**
  10. * Constructs an empty list with an initial capacity of ten.
  11. */
  12. public ArrayList() {
  13. this(10);
  14. }

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

看LinkedList的add方法:

  1. public boolean add(E e) {
  2. addBefore(e, header);
  3. return true;
  4. }
  5.  
  6. private Entry<E> addBefore(E e, Entry<E> entry) {
  7. Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
  8. newEntry.previous.next = newEntry;
  9. newEntry.next.previous = newEntry;
  10. size++;
  11. modCount++;
  12. return newEntry;
  13. }

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

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

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

来看例子:

  1. public class Array {
  2. String []myArray = {};
  3. public void SetMyArray(String []myArray){
  4. this.myArray = myArray;//这里有安全隐患
  5. }
  6.  
  7. public String[] getMyArray(){
  8. return this.myArray;//这里有安全隐患
  9. }
  10.  
  11. public static void main(String []args){
  12. Array a = new Array();
  13. String b[] = {"i "," am ","from ","china"};
  14. a.SetMyArray(b);
  15. System.out.println(a.getMyArray()[0]);
  16.  
  17. b[0]="you";
  18. System.out.println(a.getMyArray()[0]);
  19. }
  20. }

输出结果:

  1. i
  2. you

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

  1. public void SetMyArray(String []myArray){//修改后的set方法
  2. if(myArray == null){
  3. this.myArray = new String[0];
  4. }else{
  5. this.myArray = Arrays.copyOf(myArray, myArray.length);
  6. }
  7. }

此时的运行结果:

  1. i
  2. i

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

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

  1. 使用clone()方法,比如ArrayList newArray = oldArray.clone();
  2. 使用ArrayList构造方法,比如:ArrayList myObject = new ArrayList(myTempObject);
  3. 使用Collection的copy方法。

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

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

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

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

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

  1. public void add(int index, E element) {
  2. if (index > size || index < 0)
  3. throw new IndexOutOfBoundsException(
  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(int index) {
  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. return oldValue;
  14. }

Java中ArrayList相关的5道面试题的更多相关文章

  1. Java中最常见的十道面试题

    第一,谈谈final, finally, finalize的区别. final?修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此一个类不能既被声明为 ...

  2. Java中创建String的两道面试题及详解

    我们知道创建一个String类型的变量一般有以下两种方法: String str1 = "abcd"; String str2 = new String("abcd&qu ...

  3. java中ArrayList 、LinkList区别

    转自:http://blog.csdn.net/wuchuanpingstone/article/details/6678653 个人建议:以下这篇文章,是从例子说明的方式,解释ArrayList.L ...

  4. JAVA中ArrayList用法

    JAVA中ArrayList用法 2011-07-20 15:02:03|  分类: 计算机专业 |  标签:java  arraylist用法  |举报|字号 订阅     Java学习过程中做题时 ...

  5. 【Socket编程】Java中网络相关API的应用

    Java中网络相关API的应用 一.InetAddress类 InetAddress类用于标识网络上的硬件资源,表示互联网协议(IP)地址. InetAddress类没有构造方法,所以不能直接new出 ...

  6. Java中ArrayList与LinkedList的区别

    Java中ArrayList与LinkedList的区别 一般大家都知道ArrayList和LinkedList的区别: 1. ArrayList的实现是基于数组,LinkedList的实现是基于双向 ...

  7. Java中arraylist和linkedlist源代码分析与性能比較

    Java中arraylist和linkedlist源代码分析与性能比較 1,简单介绍 在java开发中比較经常使用的数据结构是arraylist和linkedlist,本文主要从源代码角度分析arra ...

  8. java中ArrayList 和 LinkedList 有什么区别

    转: java中ArrayList 和 LinkedList 有什么区别 ArrayList和LinkedList都实现了List接口,有以下的不同点:1.ArrayList是基于索引的数据接口,它的 ...

  9. 《Java面试全解析》1000道面试题大全详解(转)

    <Java面试全解析>1000道 面试题大全详解 本人是 2009 年参加编程工作的,一路上在技术公司摸爬滚打,前几年一直在上海,待过的公司有 360 和游久游戏,因为自己家庭的原因,放弃 ...

随机推荐

  1. oracle初次使用连接不上

    问题描述: win10下,cmd运行 输入sqlplus报一下错误 SP2-1503: 无法初始化 Oracle 调用界面 SP2-0152: ORACLE 不能正常工作 解决办法 cmd右键--以管 ...

  2. 怎么使用PHP获取用户客户端真实IP的解决方案呢?

    function getIp(){if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIE ...

  3. POJ 3903:Stock Exchange(裸LIS + 二分优化)

    http://poj.org/problem?id=3903 Stock Exchange Time Limit: 1000MS   Memory Limit: 65536K Total Submis ...

  4. 每日一九度之 题目1043:Day of Week

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:7336 解决:2563 题目描述: We now use the Gregorian style of dating in Russia. ...

  5. Cocos2dx框架常用单词(一)

    收集了一些Cocos2dx里面主要单词的翻译. Toggle:切换Finite:有限Instant:瞬时interval:间隔Flip:翻转place:座位,放置Target:目标reverse:反向 ...

  6. 编写一个函数func(),将此函数的输入参数(int型)逆序输出显示,如54321 –> 12345,要求使用递归,并且函数体代码不超过8行

    public class Test{ //中间变量 private String res = "0"; //方法 public int func(int i){ if(i>0 ...

  7. easyui 布局标题纵向排列

    (function($){                 var buttonDir = {north:'down',south:'up',east:'left',west:'right'};   ...

  8. 关于Java中的GUI事件处理

    关于事件监听的实现过程通过下面的代码来具体说明: package com.sxt; import java.awt.BorderLayout; import java.awt.event.Action ...

  9. asp.net 页面跳转传值的几种方式

    参考地址: http://blog.csdn.net/zzzzzzzert/article/details/8486143 protected void Button1_Click(object se ...

  10. python-学习笔记之-Day5 双层装饰器 字符串格式化 python模块 递归 生成器 迭代器 序列化

    1.双层装饰器 #!/usr/bin/env python # -*- coding: utf-8 -*- # author:zml LOGIN_INFO = False IS_ADMIN = Fal ...