首页 > java > faq > 3.java ArrayList原理及转化成数组常用方法

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]);
        }
    }
}
转载请保留原文链接.