杰瑞科技汇

Java String如何实现动态数组?

在 Java 中,并没有一个叫做 StringDynamicArray 的内置类,当开发者提到“字符串动态数组”时,通常指的是以下两种情况之一:

Java String如何实现动态数组?-图1
(图片来源网络,侵删)
  1. 一个可以动态增长/缩小的、专门用来存储 String 对象的集合类。 这是最常见的理解。
  2. 一个自己实现的、可变大小的数组数据结构,用于存放 String 这通常用于学习数据结构的目的。

下面我将围绕这两种情况进行详细解释。


使用 Java 集合框架(最常用、最推荐)

在实际开发中,我们几乎总是使用 Java 集合框架中的类来处理动态数组的需求,对于存储 String 类型,最核心、最常用的类是 ArrayList<String>

为什么选择 ArrayList<String>

  • 动态大小ArrayList 内部使用一个数组来存储元素,当元素数量超过当前数组容量时,它会自动创建一个更大的新数组,并将所有旧元素复制到新数组中,这个过程对开发者是透明的,实现了“动态”增长。
  • 类型安全:通过泛型 <String>,我们确保了这个列表中只能存放 String 对象,尝试添加其他类型(如 Integer)会在编译时报错,避免了运行时的 ClassCastException
  • 丰富的 APIArrayList 提供了大量方便的方法,如 add(), get(), set(), remove(), size() 等,操作非常简单。

ArrayList<String> 的基本用法

下面是一个完整的示例,展示了如何创建、添加、访问、修改和删除 ArrayList 中的字符串。

import java.util.ArrayList;
public class StringArrayListExample {
    public static void main(String[] args) {
        // 1. 创建一个空的 String 类型的 ArrayList
        ArrayList<String> fruits = new ArrayList<>();
        // 2. 向列表中添加元素 (动态增长)
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Orange");
        System.out.println("初始列表: " + fruits); // 输出: [Apple, Banana, Orange]
        System.out.println("当前大小: " + fruits.size()); // 输出: 3
        // 3. 在指定位置添加元素
        fruits.add(1, "Mango");
        System.out.println("在索引1处添加Mango后: " + fruits); // 输出: [Apple, Mango, Banana, Orange]
        // 4. 访问元素
        String firstFruit = fruits.get(0);
        System.out.println("第一个水果是: " + firstFruit); // 输出: Apple
        // 5. 修改元素
        fruits.set(2, "Grape");
        System.out.println("将索引2处的元素修改为Grape后: " + fruits); // 输出: [Apple, Mango, Grape, Orange]
        // 6. 删除元素
        fruits.remove("Apple"); // 删除第一个值为"Apple"的元素
        System.out.println("删除'Apple'后: " + fruits); // 输出: [Mango, Grape, Orange]
        fruits.remove(0); // 删除索引为0的元素
        System.out.println("删除索引0的元素后: " + fruits); // 输出: [Grape, Orange]
        // 7. 遍历列表
        System.out.println("使用 for-each 遍历:");
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        // 8. 检查元素是否存在
        boolean hasOrange = fruits.contains("Orange");
        System.out.println("列表中是否包含'Orange'? " + hasOrange); // 输出: true
        // 9. 清空列表
        fruits.clear();
        System.out.println("清空列表后: " + fruits); // 输出: []
        System.out.println("清空后大小: " + fruits.size()); // 输出: 0
    }
}

其他相关的集合类

除了 ArrayList,根据不同的需求,你还可以选择其他集合类:

Java String如何实现动态数组?-图2
(图片来源网络,侵删)
集合类 特点 适用场景
ArrayList<String> 基于动态数组,随机访问(get/set)速度快,增删中间元素慢。 最常用,当你需要频繁地通过索引访问元素,且不介意在中间增删元素时。
LinkedList<String> 基于双向链表,增删元素(尤其是在头部或尾部)速度快,随机访问慢。 当你需要在列表的头部或频繁进行增删操作时。
HashSet<String> 基于哈希表,元素无序唯一,查找速度极快。 当你需要存储一组不重复的字符串,且不关心它们的顺序时。
TreeSet<String> 基于红黑树,元素唯一自动排序(按字典序)。 当你需要存储一组不重复的字符串,并且希望它们总是按特定顺序(如字母顺序)排列时。

对于“字符串动态数组”,ArrayList<String> 是你的首选。


自己实现一个动态数组(学习目的)

如果你正在学习数据结构,或者想了解其底层原理,可以尝试自己实现一个简单的动态数组,这个数组将使用一个固定大小的内部数组,并在空间不足时进行扩容。

核心思想

  1. 内部存储:使用一个 String[] 数组作为底层存储。
  2. 容量与大小capacity 表示内部数组的总长度,size 表示当前存储的元素个数。
  3. 添加元素
    • size < capacity,直接在 size 位置赋值,size++
    • size == capacity,说明数组已满,需要扩容
      • 创建一个更大的新数组(通常是容量的 2 倍)。
      • 将旧数组中的所有元素复制到新数组。
      • 将新数组赋值给内部引用,并更新 capacity
      • 然后再添加新元素。
  4. 获取元素:直接通过索引访问内部数组。

简单的代码实现

这是一个非常基础的实现,只包含 addget 方法。

public class MyStringDynamicArray {
    private String[] array;
    private int size;      // 当前元素数量
    private int capacity; // 数组总容量
    // 构造函数,初始化容量
    public MyStringDynamicArray(int initialCapacity) {
        if (initialCapacity <= 0) {
            throw new IllegalArgumentException("初始容量必须大于0");
        }
        this.array = new String[initialCapacity];
        this.size = 0;
        this.capacity = initialCapacity;
    }
    // 默认构造函数
    public MyStringDynamicArray() {
        this(10); // 默认初始容量为10
    }
    // 添加元素
    public void add(String element) {
        // 检查是否需要扩容
        if (size == capacity) {
            // 扩容为原来的2倍
            resize(2 * capacity);
        }
        // 添加元素
        array[size] = element;
        size++;
    }
    // 获取元素
    public String get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("索引 " + index + " 超出范围 (0-" + (size - 1) + ")");
        }
        return array[index];
    }
    // 获取当前元素数量
    public int getSize() {
        return size;
    }
    // 获取当前容量
    public int getCapacity() {
        return capacity;
    }
    // 扩容的核心方法
    private void resize(int newCapacity) {
        String[] newArray = new String[newCapacity];
        // 将旧数组的内容复制到新数组
        for (int i = 0; i < size; i++) {
            newArray[i] = array[i];
        }
        // 更新内部数组和容量
        this.array = newArray;
        this.capacity = newCapacity;
        System.out.println("数组已扩容,新容量: " + newCapacity);
    }
    // 打印数组内容
    public void printArray() {
        System.out.print("[");
        for (int i = 0; i < size; i++) {
            System.out.print(array[i]);
            if (i < size - 1) {
                System.out.print(", ");
            }
        }
        System.out.println("]");
    }
    // 测试代码
    public static void main(String[] args) {
        MyStringDynamicArray myArray = new MyStringDynamicArray(3); // 初始容量为3
        myArray.add("Java");
        myArray.add("Python");
        myArray.add("C++");
        System.out.println("添加3个元素后:");
        myArray.printArray(); // 输出: [Java, Python, C++]
        System.out.println("大小: " + myArray.getSize() + ", 容量: " + myArray.getCapacity());
        System.out.println("\n添加第4个元素 (将触发扩容):");
        myArray.add("JavaScript");
        myArray.printArray(); // 输出: [Java, Python, C++, JavaScript]
        System.out.println("大小: " + myArray.getSize() + ", 容量: " + myArray.getCapacity());
        System.out.println("\n获取索引为1的元素: " + myArray.get(1)); // 输出: Python
    }
}
特性 ArrayList<String> (推荐) 自定义 MyStringDynamicArray
来源 Java 标准库 自己实现
易用性 非常高,API 丰富 需要自己编写所有方法
性能 经过高度优化,性能稳定 性能取决于实现,但原理相同
功能 功能强大(排序、查找、删除等) 功能需要自己扩展
适用场景 所有日常和商业开发 学习数据结构和算法

在实际项目中,请毫不犹豫地使用 ArrayList<String>,它经过了数百万开发者测试,性能可靠,功能强大,能让你专注于业务逻辑而不是底层实现,自己动手实现一个动态数组,则是一个极好的编程练习,能让你深刻理解其工作原理。

Java String如何实现动态数组?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇