数组(二):ArrayList的实现和Arrays类的使用
来源:互联网 发布:烂命鸳鸯知乎 编辑:程序博客网 时间:2024/05/29 07:47
一、数组是否可以变长?
我们都知道,数组时定长的,初始化时一定要给定长度,由于这个长度的问题,我们在实际的开发中,会更倾向于使用容器,如ArrayList等,使用容器类时,无需考虑长度问题,因为容器已经帮我们处理了,那么数组就没有办法变长了吗?当然不是,ArrayList就是基于数组实现的,我们可以看看ArrayList是如何处理的
二、ArrayList的实现原理
ArrayList用一个Object数组作为其内部操作,并有一个成员变量size代表容器的长度
private transient Object[] elementData; private int size;
添加数据时,调用add()方法:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
private void ensureCapacityInternal(int minCapacity) { modCount++; // 如果添加了新元素后的长度超出了原来的长度,则需要扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); }
可以看到扩容的核心代码在grow方法中:
private void grow(int minCapacity) { int oldCapacity = elementData.length; //扩容,生成新容量,为原来的2倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 把数组扩大到新长度 elementData = Arrays.copyOf(elementData, newCapacity); }
elementData = Arrays.copyOf(elementData, newCapacity)
API文档的解释是:复制指定的数组,截取或用 null 或 0 填充(如有必要),以使副本具有指定的长度
也就是说,通过Arrays.copyOf,将数组elementData的长度扩大到newCapacity,扩大的部分填充由数组类型决定
例如:
int[] a = new int[]{1,2}; System.out.println("扩容前长度:" + a.length); a = Arrays.copyOf(a, 3); System.out.println("扩容后长度:" + a.length); System.out.println("填充的数据:" + a[2]);
输出:
扩容前长度:2
扩容后长度:3
填充的数据:0
我们来查看一下Arrays.copyOf源代码,看看它做了什么:
public static int[] copyOf(int[] original, int newLength) { int[] copy = new int[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
Arrays.copyOf方法中,重新创建了一个新长度的数组,并且通过System.arraycopy方法把原来的数组复制到新数组中,最后返回。System.arraycopy是一个本地的系统方法,采用的是直接对内存中的数据块进行复制,是一块一块复制的(操作系统中有讲到),所以比我们平时for循环一个一个复制要快得多。
三、效率
值得注意这些问题,什么时候会扩容?扩容会影响效率吗?如果影响要怎么避免?
当增加元素后的size 大于 原来的size时,就需要扩容,而扩容需要复制数组,小数据量还好,而大数据量的时候肯定很影响效率!注意到,ArrayList中有两个和size相关构造函数:
public ArrayList() { this(10); } public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; }
第一个构造函数给定默认容量size为10,而第二个函数默认size自定义,那么我们看这两个构造函数在大数据量的情况:
public abstract class Array1 { public static void main(String[] args) { long b1 = System.currentTimeMillis(); List<Integer> list1 = new ArrayList<Integer>(); for(int i =0; i < 10000000; i++){ list1.add(i); } long e1 = System.currentTimeMillis(); System.out.println("时间为 : " + (e1-b1)); long b2 = System.currentTimeMillis(); List<Integer> list2 = new ArrayList<Integer>(10000000); for(int i =0; i < 10000000; i++){ list2.add(i); } long e2 = System.currentTimeMillis(); System.out.println("时间为 : " + (e2-b2)); }}
结果如下:
时间为 : 7878
时间为 : 283
所以:请为你的ArrayList指定初始容量!
三、Arrays类的使用
Arrays类包含用来操作数组(比如排序和搜索)的各种方法,这个类是必须熟练使用的!
该类的常用方法有:
以上只用int类型数组做为example,同理其他类型数组同样的操作
四、copyOf的陷阱,数组的浅拷贝
当数组类型不是基本数据类型时,数组内存放的是对象的引用,因此在copyOf复制对象数组时,千万要注意,复制的对象的引用而不是对象本身!
class Person{ int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; }}public class Array2 { public static void main(String[] args) { Person p = new Person(); p.setAge(20); Person[] a = new Person[]{p}; Person[] b = Arrays.copyOf(a, a.length); a[0].setAge(30); System.out.println("a的年龄:" + a[0].getAge()); System.out.println("b的年龄:" + b[0].getAge()); }}
输出:
a的年龄:30
b的年龄:30
可以看见,a改变其值后,连b的值都改变了,这就是浅拷贝问题
有关于深浅拷贝的博文,参考:
渐析java的浅拷贝和深拷贝:http://www.cnblogs.com/chenssy/p/3308489.html。
- 数组(二):ArrayList的实现和Arrays类的使用
- Arrays.copy()和ArrayList.clone()的使用区别
- ArrayList的使用(二)
- ArrayList数组的使用
- ArrayList动态数组的使用和遍历
- Arrays类操作数组的使用
- 熟练使用Arrays-数组-ArrayList-HashMap等常用Java类型的方法
- ArrayList和Iterator的初步使用(二)
- 数组资源(arrays)的使用
- 数组资源(arrays)的使用
- java关于ArrayList动态数组与静态数组Arrays-元素比较输出最大最小值的使用例子
- 动态数组的实现-ArrayList
- Arrays类(数组操作的类)
- Arrays(数组的工具类)
- 自己理解的java.util.ArrayList(二)实现类
- ArrayList和数组的区别
- 数组和ArrayList的区别
- ArrayList和数组的互换
- 机器学习-数据归一化方法
- 修改hdfs上目录的权限
- 1102: 整数幂(C语言输出左对齐格式)
- Hibernate 一对一主键单向关联
- 关于 safari浏览器 不支持new Date 显示NaN的问题记录
- 数组(二):ArrayList的实现和Arrays类的使用
- LintCode 主元素
- yolo v2 笔记
- 排序算法
- tcp、http 学习小结
- PC机安装ArchLinux详细步骤
- window系统,wamp下nginx配置TP使用
- Hibernate 一对一连接表单向关联
- PHP强制下载文件