对象数组 Java

⚡ 智能摘要

对象数组 Java 将对象引用存储在固定大小的连续槽中,允许单个变量保存类的多个实例,并通过索引访问每个实例以进行迭代、修改和传递给方法。

  • 📦 参考存储: 每个槽位 Java 对象数组保存的是对对象的引用,而不是对象本身,这与任何对象变量类似。 Java.
  • 🧱 两步创建: 使用 new ClassName[size] 分配数组,然后在调用方法之前使用 new ClassName() 分配每个对象。
  • ⚠️ 空指针异常: 每个槽位初始状态均为 null。对未初始化的槽位调用方法会在运行时抛出 NullPointerException 异常。
  • 🔁 迭代: 使用带有数组长度的 for 循环或增强型 for 循环遍历数组中的每个对象。
  • 📏 固定尺寸: 数组分配后无法增长。当对象数量在运行时发生变化时,请使用 ArrayList。
  • ????️ 构造函数初始化: 在创建过程中内联传递构造函数,比事后调用 setter 方法能提供更短、更安全的设置。
  • 🚚 方法参数: 将数组传递给方法会传递引用,因此方法内部的更改对调用者是可见的。

对象数组 Java

什么是对象数组? Java?

A Java 对象数组 它将同一类的多个对象实例存储在一个固定大小的容器中。这与存储诸如值之类的原始数组不同。 int, double 或 boolean 每个槽位直接存储一个对象数组。 引用每个槽位都指向一个对象的内存位置,而对象本身则存在于该位置。 Java 堆。

这种布局与任何对象的布局方式相匹配 变量 in Java 数组确实有效。它只是将多个对象引用组合在一起,以便您可以通过索引访问它们。当对象数量预先已知且在程序运行期间保持不变时,数组是自然之选。

句法

ClassName[] obj = new ClassName[array_length];

右侧预留空间用于 array_length 所有引用均已初始化。 null. 不涉及 ClassName 目前仅存在能够保存对这类对象引用的容器。

如何在代码中创建对象数组 Java

创建一个工作对象数组总是需要两个分配步骤。第一步分配引用容器,第二步分配容器将指向的每个对象。跳过ping 第二步是最常见的单一来源 NullPointerException 初学者 Java 码。

步骤1) 打开你的 代码编辑器 并复制以下代码:

class ObjectArray {
    public static void main(String args[]) {
        Account obj[] = new Account[2];
        // obj[0] = new Account();
        // obj[1] = new Account();
        obj[0].setData(1, 2);
        obj[1].setData(3, 4);
        System.out.println("For Array Element 0");
        obj[0].showData();
        System.out.println("For Array Element 1");
        obj[1].showData();
    }
}

class Account {
    int a;
    int b;

    public void setData(int c, int d) {
        a = c;
        b = d;
    }

    public void showData() {
        System.out.println("Value of a = " + a);
        System.out.println("Value of b = " + b);
    }
}

步骤2) 将文件保存为 ObjectArray.java然后编译并运行它。

步骤3) 注意错误。在继续执行步骤 4 之前,请尝试调试该错误。

步骤4) 检查线路 Account obj[] = new Account[2];它分配一个包含两个类型引用变量的数组。 Account但它不分配任何 Account 物品。两个槽位均可存放物品。 null并呼叫 obj[0].setData(...) 上 null 引用抛出异常 NullPointerException 在运行时。

Java 对象数组引用变量

步骤5) 取消注释第 4 行和第 5 行。这两行会创建实际的 Account 对象并将它们分配给 obj[0] 和 obj[1]数组现在包含实际引用,代码运行正常。

Java 已填充对象数组

输出:

For Array Element 0
Value of a = 1
Value of b = 2
For Array Element 1
Value of a = 3
Value of b = 4

如何在代码中初始化对象数组 Java

除了上面提到的基于 setter 的初始化方法之外,对象数组还可以用三种更简洁的方式进行初始化。每种方法都以牺牲代码简洁性为代价,因此请选择最适合具体情况的方法。

  1. 循环初始化 — 先分配数组,然后遍历每个索引并分配一个新的对象。这是大型数组或对象数量动态变化时的标准模式。
  2. 构造函数初始化 — 在创建时直接将值传递给构造函数,因此不需要单独调用 setter。
  3. 数组字面量初始化 — 使用内联语句在单个语句中声明和填充。 { ... } 初始化器,非常适合小型固定装置。
class Account {
    int a, b;

    public Account(int a, int b) {   // constructor
        this.a = a;
        this.b = b;
    }
}

public class InitDemo {
    public static void main(String[] args) {

        // 1) Loop initialisation
        Account[] loopArr = new Account[3];
        for (int i = 0; i < loopArr.length; i++) {
            loopArr[i] = new Account(i, i * 10);
        }

        // 2) Constructor initialisation, one slot at a time
        Account[] ctorArr = new Account[2];
        ctorArr[0] = new Account(1, 2);
        ctorArr[1] = new Account(3, 4);

        // 3) Array literal initialisation
        Account[] litArr = {
            new Account(5, 6),
            new Account(7, 8),
            new Account(9, 10)
        };

        System.out.println("loop size   = " + loopArr.length);
        System.out.println("ctor size   = " + ctorArr.length);
        System.out.println("literal size= " + litArr.length);
    }
}

循环初始化是最安全的默认设置,因为它保证不会遗漏任何槽位。 null构造函数初始化可以明确地表明每个对象需要不同参数的意图,而数组字面量则能保持小型示例代码的简洁性。除非有特殊原因,否则不要在同一个数组中混用不同的类型:保持一致性有助于更容易地发现错误。

迭代和访问元素 Java 对象数组

一旦对象数组被填充完毕,三种模式几乎可以满足所有访问需求。选择循环方式时,应根据代码对索引的控制程度来决定。

经典口味 for 循环 提供对索引的访问,这对于替换元素、比较相邻元素或迭代子范围非常有用。

for (int i = 0; i < obj.length; i++) {
    System.out.println("Element " + i);
    obj[i].showData();
}

品牌影响力提升 for 循环 (“for-each”循环)隐藏了索引,在不需要索引时,代码读起来更自然:

for (Account acc : obj) {
    acc.showData();
}

流(Java 8 及以后) 将数组转换为管道,这对于过滤和映射非常有用。ping或者,无需编写循环即可进行聚合:

import java.util.Arrays;

Arrays.stream(obj)
      .filter(acc -> acc.a > 0)
      .forEach(Account::showData);

要读取或更新单个元素,请使用直接索引访问,例如 obj[1].setData(10, 20)务必先用……检查长度 obj.length 避免 ArrayIndexOutOfBoundsException当任何槽位都可能出现时 null使用空值检查或 Optional 保持程序运行,避免崩溃。

对象数组与对象 ArrayList 的区别 Java

普通的对象数组速度快、可预测,但一旦运行时对象数量发生变化,其固定大小就会成为一种限制。 Java's Collections 框架提供 ArrayList 作为动态替代方案。下表列出了每种选择的适用情况。

特性对象数组对象数组列表
尺寸创建时已固定自动增大和缩小
声明Account[] a = new Account[5];List<Account> list = new ArrayList<>();
访问元素a[i]list.get(i)
添加元素创建后不支持list.add(obj)
类型安全编译时类型声明泛型在编译时强制执行
性能索引读取速度略微加快摊销 O(1) 增加,每个元素有一些开销
首选尺寸已知且固定大小未知或运行时会发生变化。

当内存占用小且索引可预测至关重要时,例如在矩阵布局或对性能要求极高的热路径中,请使用数组。 ArrayList 在大多数日常应用程序代码中,因为无需重新分配即可添加和删除内存的能力超过了每个元素的小开销。

常见问题

一个对象数组 Java 是一个固定大小的容器,用于存储对同一类实例的引用。每个槽位指向堆上的一个对象,元素通过方括号内的从零开始的索引进行访问。

首先声明数组 `ClassName[] arr = new ClassName[size]`,然后在循环中使用 `new ClassName()` 或使用内联数组字面量创建每个对象。这两个步骤都是必需的;第一步只会分配引用槽。

因为 `new ClassName[size]` 只会分配数组本身。每个槽位初始值为 `null`,所以调用该槽位上的任何方法都会抛出 `NullPointerException`。解决方法是在使用前为每个索引分配一个 `new ClassName()`。

数组的大小在创建时就已固定,而 ArrayList 会自动增长和收缩。数组的索引读取速度略快;ArrayList 为日常应用程序代码提供了便捷的添加、删除和流式传输方法。

需要获取数组索引时,可以使用经典的 for 循环并加上 arr.length;对于简单的迭代,可以使用增强型的 for-each 循环。对于过滤或转换操作,可以使用 Arrays.stream(arr) 将数组包装起来,然后链接所需的管道。

将参数声明为 ClassName[] name,然后使用该数组变量调用该方法。 Java 按值传递数组引用,因此方法内部对元素字段的修改对调用者是可见的。

机器学习代码生成器能够识别两步分配模式,并补全初学者容易忽略的缺失的 `new ClassName()` 语句。此外,当目标集合大小未知时,它们还会建议使用 `ArrayList`,从而减少 `NullPointerException` 异常的发生。

是的。GitHub Copilot 会根据描述领域模型的注释生成数组声明、构造函数循环、迭代块和 ArrayList 转换。 Rev使用前,请查看生成的代码,以确保构造函数参数正确且空值处理安全。

总结一下这篇文章: