数组和 List 两家是邻居,同时它俩也是同班同学。两人最近很苦恼,因为父母最近经常说:“你看看对门邻居XXX,你就不能好好学学人家?”。它们的父母之所以这个说是因为加瓦老师最近举行的两次考试,一次考试 List 考出了好成绩,另一次考试数组考出了好成绩。具体是什么样的考试呢,我们下面来看一下。
零、考试题目
首先,第一次考试的题目是这样的:请在最短的时间内将 Integer 类型的数字 0 到 100000000 放入自己的口袋内。考试一分一秒的过去了数组用了 171 毫秒完成了考题,而 List 却用了 22147 毫秒才完成考题,于是加瓦老师判定数组第一名。
不久,第二次考试来了,题目是这样的:请在最短的时间内将 String 类型的数字 0 到 100000000 放入自己的口袋。这次考试 List 用了 3825 毫秒,而数组却用了 67337 毫秒,因此加瓦老师判定 List 第一名。
一、解析
前面给大家讲了一个小故事,看完这个故事大家一定很纳闷,同样是数字,为什么两次考试数组和 List 执行的时间相差这么大呢?要解释这个问题,首先我们先把上面的两道题转换为 Java 代码。
//题目一
public class ExamOne
{
public static void main(String[] args) {
long start=System.currentTimeMillis();
insertArray();
long end=System.currentTimeMillis();
System.out.println(end-start);
insertList();
System.out.println(System.currentTimeMillis()-end);
}
static void insertArray() {
int[] nums = new int[100000000];
for(int i=0;i<100000000;i++) {
nums[i]=i;
}
}
static void insertList() {
List<Integer> nums=new ArrayList<Integer>();
for(int i=0;i<100000000;i++) {
nums.add(i);
}
}
}
//题目二
public class ExamTwo
{
public static void main(String[] args) {
long start=System.currentTimeMillis();
insertArray();
long end=System.currentTimeMillis();
System.out.println(end-start);
insertList();
System.out.println(System.currentTimeMillis()-end);
}
static void insertArray() {
String[] nums = new String[100000000];
for(int i=0;i<100000000;i++) {
nums[i]=""+i;
}
}
static void insertList() {
List<String> nums=new ArrayList<String>();
for(int i=0;i<100000000;i++) {
nums.add(""+i);
}
}
}
上述代码我们还原了两次考试 List 和数组的解题过成,看似简单其实内部暗藏玄机。首先,我们来看一下题目一中的玄机,在 insertList 方法中我们定义了一个 Integer 类型 List 变量 nums ,并通过 for 循环的方式向 nums 中插入数值。然而这里有一个非常影响性能的问题,我们定义的 nums 只能存放 Integer 对象型的变量,如果要将 int 类型的 i 插入进去就必须进行拆箱装箱操作,进而影响到了性能。第二道题呢我们将 nums 便令定义为 String 类型的变量,并且在循环插入时插入的也是 String 类型 (""+i),这样就避免了拆箱装箱的操作,提高了性能。
二、总结
这篇文章主要讲解数组和 List ,这类问题经常面试中会被问到,我们只需要记住:在 Java 中 set 、 map 、 list 等这类的数据机构只能存放引用对象,如果碰到了数值类型的对象就会发生拆箱装箱操作,虽然少量的数据不会影响程序的整体性能,但是当数据量巨大的时候就会影响到程序的整体性能。