JavaArrayList 和 Array(数组)的区别?

ArrayList 和 Array 是两种常见的数据结构,它们在许多方面有所不同。本文将详细讲解二者的区别,并通过代码示例和源码分析来深入理解这些差异。

1. 动态扩容 vs 固定长度

Array

Array 是一种固定长度的数据结构,数组在创建时必须指定其大小,且一旦创建便不能改变其长度。以下是一个简单的示例:

java

// 初始化一个 String 类型的数组
String[] stringArr = new String[]{"hello", "world", "!"};
System.out.println(Arrays.toString(stringArr)); // 输出: [hello, world, !]

// 修改数组元素的值
stringArr[0] = "goodbye";
System.out.println(Arrays.toString(stringArr)); // 输出: [goodbye, world, !]

// 删除数组中的元素,需要手动移动后面的元素
for (int i = 0; i < stringArr.length - 1; i++) {
    stringArr[i] = stringArr[i + 1];
}
stringArr[stringArr.length - 1] = null;
System.out.println(Arrays.toString(stringArr)); // 输出: [world, !, null]
ArrayList

ArrayList 是基于动态数组实现的,它的大小可以根据需要动态增长和缩减。以下是一个简单的示例:

java

// 初始化一个 String 类型的 ArrayList
ArrayList<String> stringList = new ArrayList<>(Arrays.asList("hello", "world", "!"));
System.out.println(stringList); // 输出: [hello, world, !]

// 添加元素到 ArrayList 中
stringList.add("goodbye");
System.out.println(stringList); // 输出: [hello, world, !, goodbye]

// 修改 ArrayList 中的元素
stringList.set(0, "hi");
System.out.println(stringList); // 输出: [hi, world, !, goodbye]

// 删除 ArrayList 中的元素
stringList.remove(0);
System.out.println(stringList); // 输出: [world, !, goodbye]

2. 类型安全 vs 非类型安全

Array

Array 可以存储基本类型数据和对象,但不支持泛型。以下是一个例子:

java

int[] intArray = new int[]{1, 2, 3}; // 基本类型数组
String[] stringArray = new String[]{"hello", "world"}; // 对象类型数组
ArrayList

ArrayList 允许使用泛型来确保类型安全,只能存储对象类型的数据。对于基本类型数据,需要使用其对应的包装类(如 IntegerDouble 等):

java

ArrayList<Integer> intList = new ArrayList<>(Arrays.asList(1, 2, 3)); // 泛型 ArrayList
ArrayList<String> stringList = new ArrayList<>(Arrays.asList("hello", "world")); // 泛型 ArrayList

3. 丰富的 API 支持 vs 基础操作

Array

Array 只提供基础的数组操作,无法动态添加、删除元素。以下是一个示例:

java

String[] stringArray = new String[]{"hello", "world"};
// 访问数组元素
String firstElement = stringArray[0];
// 修改数组元素
stringArray[0] = "hi";
ArrayList

ArrayList 提供了丰富的 API 操作方法,如 add()remove()set() 等:

java

ArrayList<String> stringList = new ArrayList<>(Arrays.asList("hello", "world"));
// 添加元素
stringList.add("goodbye");
// 删除元素
stringList.remove("world");
// 修改元素
stringList.set(0, "hi");

4. 内部实现和扩容机制

ArrayList 的源码解析

ArrayList 的内部是基于数组实现的,但它提供了动态扩容的机制。以下是 ArrayList 的部分源码和其扩容机制的解析:

java

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    // 底层数组
    transient Object[] elementData;

    // 当前元素个数
    private int size;

    // 默认初始容量
    private static final int DEFAULT_CAPACITY = 10;

    // 最大数组大小
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    // 添加元素的方法
    public boolean add(E e) {
        ensureCapacityInternal(size + 1); // 扩容检查
        elementData[size++] = e;
        return true;
    }

    // 确保容量
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    // 扩容方法
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容为原来的1.5倍
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }
}

在 ArrayList 中,当我们调用 add() 方法时,如果当前数组容量不足以容纳新元素,ArrayList 会自动调用 grow() 方法进行扩容,默认扩容为原来容量的1.5倍。这种机制使得 ArrayList 能够动态地调整大小,具有很高的灵活性。

总结

通过以上对比和源码解析,可以清晰地看到 ArrayList 和 Array 的差异:

  • ArrayList 支持动态扩容,Array 是固定长度的。
  • ArrayList 允许使用泛型,确保类型安全,Array 不支持泛型。
  • ArrayList 提供了丰富的 API 操作方法,Array 只能进行基础操作。
  • ArrayList 内部实现基于数组,并通过扩容机制实现动态调整大小。

在实际开发中,如果需要一个固定大小的数组,且对性能要求较高,可以选择 Array。如果需要一个可以动态调整大小的集合,并且需要丰富的操作方法,可以选择 ArrayList

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值