授课语音

静态数组和动态数组

1. 引言

在计算机科学中,数组是一种用于存储多个相同类型元素的数据结构。根据数组的内存分配方式和大小的可变性,数组可以分为静态数组动态数组两种类型。它们在内存管理和使用灵活性上有很大的不同。今天我们将详细介绍静态数组和动态数组的概念、特点、使用场景以及Java中的具体实现。

2. 静态数组

2.1 静态数组的概念

静态数组(Static Array)是指在编译时已经确定大小并且在程序运行过程中不能更改大小的数组。在静态数组中,一旦数组的大小被指定,就不能再修改它的大小。它通常使用一个固定的内存块来存储数据,因此其大小是固定的,不能动态扩展。

2.2 静态数组的特点

  • 固定大小:静态数组的大小在创建时就已经确定,无法在运行时修改。
  • 内存连续:数组中的元素在内存中是连续存储的,这样可以提高访问效率。
  • 性能较高:由于静态数组在内存中是连续的,访问速度较快,通常具有更好的缓存局部性。
  • 内存浪费:如果数组的实际使用元素比预定大小少,可能会浪费内存;反之,若实际使用元素多于预定大小,会出现数组越界错误。

2.3 Java中的静态数组

在Java中,静态数组的声明与初始化非常简单。可以通过指定数组的大小来创建静态数组。Java中没有原生的“静态数组”类型,但通过定义一个固定大小的数组,我们可以模拟静态数组。

示例代码:

public class StaticArrayExample {
    public static void main(String[] args) {
        // 声明一个大小为5的整数数组
        int[] staticArray = new int[5];
        
        // 初始化数组元素
        staticArray[0] = 10;
        staticArray[1] = 20;
        staticArray[2] = 30;
        staticArray[3] = 40;
        staticArray[4] = 50;

        // 输出数组元素
        for (int i = 0; i < staticArray.length; i++) {
            System.out.println("Element at index " + i + ": " + staticArray[i]);
        }
    }
}

解释:

  • 我们声明了一个大小为5的数组 staticArray,并手动为每个元素赋值。
  • 数组的大小一旦确定,就不能再改变。
  • 访问数组元素时,通过索引来访问,每次访问是 O(1) 的时间复杂度。

3. 动态数组

3.1 动态数组的概念

动态数组(Dynamic Array)是一种可以在程序运行时根据需求改变大小的数组。当动态数组的空间不足时,它可以自动扩展其容量,通常是扩展到原来大小的两倍。动态数组提供了更高的灵活性,适用于元素数量不确定的场景。

3.2 动态数组的特点

  • 可变大小:动态数组的大小可以根据实际需求动态扩展或收缩,因此具有较好的灵活性。
  • 内存分配:动态数组通常采用连续内存块来存储数据,当空间不足时,数组会自动扩展,并将旧数组的数据复制到新数组中。
  • 性能开销:扩展动态数组时,需要分配新的内存并复制原数组的数据,这个操作会导致一定的性能开销。
  • 内存效率:动态数组的内存分配灵活,适应了不同大小的需求,避免了静态数组可能出现的内存浪费问题。

3.3 Java中的动态数组

Java提供了ArrayList类,它是一个动态数组实现,可以在运行时动态调整大小。ArrayList类可以根据需要自动扩展容量,并允许在末尾插入、删除元素。

示例代码:

import java.util.ArrayList;

public class DynamicArrayExample {
    public static void main(String[] args) {
        // 创建一个动态数组(ArrayList)
        ArrayList<Integer> dynamicArray = new ArrayList<>();

        // 向数组中添加元素
        dynamicArray.add(10);
        dynamicArray.add(20);
        dynamicArray.add(30);
        dynamicArray.add(40);
        dynamicArray.add(50);

        // 输出数组元素
        for (int i = 0; i < dynamicArray.size(); i++) {
            System.out.println("Element at index " + i + ": " + dynamicArray.get(i));
        }

        // 向数组中添加更多元素,动态扩容
        dynamicArray.add(60);
        dynamicArray.add(70);

        // 输出扩容后的数组元素
        System.out.println("\nAfter adding more elements:");
        for (int i = 0; i < dynamicArray.size(); i++) {
            System.out.println("Element at index " + i + ": " + dynamicArray.get(i));
        }
    }
}

解释:

  • 我们创建了一个ArrayList类型的动态数组,并通过add()方法向其中添加元素。
  • 与静态数组不同,ArrayList的大小可以根据需要动态调整,不需要手动指定大小。
  • 当数组空间不足时,ArrayList会自动扩展容量,并将现有元素复制到新的内存空间中。

3.4 ArrayList 扩展原理

ArrayList的扩展通常是通过以下方式实现的:

  • ArrayList的容量不足时,它会创建一个新的数组,大小通常是当前数组大小的两倍。
  • 然后将旧数组中的元素复制到新数组中,释放旧数组的内存。
  • 这种操作通常会带来一定的性能开销,但它使得ArrayList能够灵活地处理不断增长的元素。

4. 静态数组与动态数组的比较

特性 静态数组 动态数组
大小 固定,初始化时确定 可动态扩展
内存分配 固定大小的连续内存块 随着数据增加动态扩展
访问速度 快速,直接通过索引访问 一般与静态数组相同
扩展性 不支持动态扩展 支持自动扩展
适用场景 数量已知且不变的元素 元素数量不确定,变化较大的场景
性能开销 没有扩展的开销 在扩展时有一定性能开销

5. 总结

  • 静态数组适用于元素数量固定且在运行时不发生变化的情况,具有较高的访问性能,但缺乏灵活性。
  • 动态数组适用于元素数量变化较大的情况,能够在需要时自动扩展,但由于扩展操作的开销,性能上可能稍差。

在实际开发中,如果知道元素数量不会发生变化,可以使用静态数组。如果元素数量不确定,或者需要频繁添加元素,使用动态数组会更加高效和灵活。Java中的ArrayList就是一个非常常见的动态数组实现,它提供了非常方便的接口来操作数组。

6. 练习

  1. 问题:编写一个Java程序,使用静态数组存储10个整数,并计算它们的总和和平均值。

  2. 问题:编写一个Java程序,使用ArrayList存储10个整数,计算它们的总和和平均值,并输出。

  3. 问题:创建一个静态数组,使用插入排序对其进行排序,然后输出排序后的数组。

  4. 问题:扩展动态数组的功能,在每次元素添加时,输出当前ArrayList的大小和容量(通过ArrayListsize()方法和toArray().length来获取容量)。

通过这些习题,可以加深对静态数组和动态数组的理解,并实践如何在Java中实现它们。

去1:1私密咨询

系列课程: