3.java ArrayList原理及转化成数组常用方法
在实际项目中会用根据需求用到ArrayList和数组之间的转换。比如往MongoDB数据库中存入一个整型数组(int[]),读取的时候可以得到一个ArrayList ,无法直接得到一个整型数组(int[]).这个时候就会需要用到ArrayList转化为数组.
1 ArrayList底层原理
ArrayList底层是是一个变长数组,随着add方法加入的元素数量增加会增加内部数组的长度。
1.1 ArrayList内部存储对象
ArrayList内部存储对象是一个Object数组(Object[]).
transient Object[] elementData; // non-private to simplify nested class access
这里用到了transient关键字。参考transient关键字的作用
1.2 ArrayList检测内部容量
ArrayList通过add方法添加对象时,会检测内部容量。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal方法来检测内部对象数组的长度,不足的话,扩容。
ArrayList默认长度定位为10
private static final int DEFAULT_CAPACITY = 10;
1.3 ArrayList内部数组扩容
ArrayList通过grow方法扩容。扩容时,扩大当前容量的两倍。这个长度是通过位运算计算得出的。
int newCapacity = oldCapacity + (oldCapacity >> 1);
grow方法源码:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
1.4 ArrayList的get方法原理
ArrayList的get方法原理是通过数组下标获取数组中对应的对象。get方法源码:
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
elementData方法源码:
E elementData(int index) {
return (E) elementData[index];
}
2 ArrayList转化为数组常用方式
ArrayList转化为数组有几种常用方式:遍历ArrayList转化数组, ArrayList.toArray()方法,带参数的ArrayList.toArray(Object[])方法.
2.1 遍历ArrayList转化数组
这种是最容易理解的方式。
int[] arr0 = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
arr0[i] = list.get(i);
}
2.2 ArrayList.toArray()方法
ArrayList.toArray()方法会返回Object[]数组,无法强转为对应数组.
Object[] arr1 = list.toArray();
如果强转成对应类型的对象数组会怎样呢? 答案是会抛出异常.如果把以上代码改为:
Integer[] arr1 = new Integer[list.size() - 10];
编译程序时会报java.lang.ClassCastException异常.
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
at com.dashidan.faq3.Demo1.main(Demo1.java:30)
这种方式获取的数组,可以在遍历数组对象时候进行强转.
2.2 ArrayList.toArray(Object[])方法
ArrayList工具类还提供一个带参数的转化数组的方法ArrayList.toArray(Object[])。这个方法需要事先定义好转化的数组对象类型,让后将ArrayList中对象复制到该数组中.
Integer[] arr1 = new Integer[list.size()];
list.toArray(arr1);
使用这种方式的转化的时候要注意:创建的数组对象长度最好和list的长度一直,如果小于list的长度,得到的数组中的对象为空,超过list长度,会用空位填充。
将上述代码改为长度减10:
Integer[] arr1 = new Integer[list.size()-10];
这样得到的数组长度为90,但内部对象都是空
将上述代码改为长度加10:
Integer[] arr1 = new Integer[list.size()+10];
这样得到的数组长度为110,前100个与list中的数据对应,后10个用null填充。
3 数组转化为ArrayList
可以通过for循环遍历数组,插入ArrayList来实现.
/** 数组转化为ArrayList*/
int[] aaa = new int[100];
ArrayList bbb = new ArrayList<Integer>();
for (int i = 0; i < aaa.length; i++) {
bbb.add(aaa[i]);
}
4 完整示例代码
package com.dashidan.faq3;
import java.util.ArrayList;
/**
* 大屎蛋教程网-dashidan.com
* 3.java ArrayList转化为数组
* Created by 大屎蛋 on 2018/5/24.
*/
public class Demo1 {
public static void main(String[] args) {
/** 初始化ArrayList*/
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add(i);
}
/** 1 遍历ArrayList转化数组*/
int[] arr0 = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
arr0[i] = list.get(i);
}
/** 2 ArrayList.toArray() 方法转化数组*/
Object[] arr1 = list.toArray();
/** 3 ArrayList.toArray(T[] a)方法转化数组*/
Integer[] arr2 = new Integer[list.size() + 10];
list.toArray(arr2);
/** 数组转化为ArrayList*/
int[] aaa = new int[100];
ArrayList bbb = new ArrayList<Integer>();
for (int i = 0; i < aaa.length; i++) {
bbb.add(aaa[i]);
}
}
}