Java 对象创建的几种方式

2025年3月17日 | 阅读 7 分钟

Java 中创建对象的五种不同方式

  • Java new 操作符
  • Java Class.newInstance() 方法
  • Java constructor 的 newInstance() 方法
  • Java Object.clone() 方法
  • Java 对象序列化和反序列化

1) Java new 操作符

这是 Java 中创建对象的流行方式。 new 操作符后面会跟着一个构造函数的调用,该构造函数会初始化新对象。当创建对象时,它会在堆中占用空间。

语法

Java new 操作符示例

输出

How many Ways to Create an Object in Java

2) Java Class.newInstance() 方法

Java 的 Class.newInstance() 是 Class 类的方法。Class 类属于 java.lang 包。它创建一个由该 Class 对象表示的新类的实例。它返回新创建的类实例。

语法

如果类或其无参构造函数不可访问,则抛出 IllegalAccessException。如果 Class 表示一个抽象类、接口、数组类或基本类型,则它还会抛出 InstantiationException

示例

输出

How many Ways to Create an Object in Java

3) Constructor 类的 newInstance() 方法

Java 的 Constructor 类也像 Class 类的 newInstance() 方法一样拥有一个 newInstance() 方法。newInstance() 方法属于 java.lang.reflect.Constructor 类。两个 newInstance() 方法都称为创建对象的反射方式。事实上,Class 类的 newInstance() 方法内部使用了 Constructor 类的 newInstance() 方法。该方法通过调用构造函数返回一个新创建的对象。

语法

newInstance() 方法抛出以下异常

  • IllegalAccessException: 如果构造函数不可访问。
  • IllegalArgumentException: 如果实际参数和形式参数的数量不同。
  • InstantiationException: 如果构造函数表示一个抽象类。
  • InvocationTargetException: 如果底层构造函数抛出异常。
  • ExceptionInInitializerError: 如果此方法引发的初始化失败。

示例

输出

How many Ways to Create an Object in Java

4) Java Object.clone() 方法

Java 的 clone() 方法创建现有对象的副本。它定义在 Object 类中。它返回此实例的克隆。关于 clone() 方法的两个最重要的点是:

  • 使用 clone() 方法时必须实现 Cloneable 接口。它定义在 java.lang 包中。
  • 必须在其他类中重写 clone() 方法。

当我们在类中使用 clone() 方法时,该类必须调用 super.clone() 来获取克隆的对象引用。

语法

如果 Object 类不支持 Cloneable 接口,该方法将抛出 CloneNotSupportedException。当覆盖 clone() 方法的子类指示实例无法克隆时,也会抛出此异常。

示例

输出

How many Ways to Create an Object in Java

5) Java 对象序列化和反序列化

一个类必须实现 Serializable 接口,该接口属于 java.io 包。Serializable 接口没有任何方法和字段。它们为类添加了特殊行为。Java 8 中不再使用标记接口。它由注解取代。

每当我们序列化和反序列化对象时,JVM 都会创建一个单独的空间。它不使用任何构造函数来创建对象。

对象序列化

ObjectOutputStream 类用于序列化对象。序列化是将对象转换为字节序列的过程。

ObjectOutputStream 类的 writeObject() 方法序列化对象并将指定的对象写入 ObjectOutputStream 类。该方法的签名是:

该方法接受一个对象作为参数。

对象反序列化

从字节序列创建对象的过程称为对象反序列化。ObjectInputStream 类的 readObject() 方法从 ObjectInputStream 类读取对象并将其反序列化。该方法的签名是:

该方法不接受任何参数。它返回从流中读取的对象。该方法抛出以下异常:

  • ClassNotFoundException: 如果找不到序列化对象的类。
  • InvalidClassException: 序列化使用的类存在问题。
  • IOException: 任何常见的与输入/输出相关的异常。
  • OptionalDataException: 如果在流中找到基本数据而不是对象。

示例

在下面的示例中,我们首先序列化了对象,然后反序列化了对象。

输出

How many Ways to Create an Object in Java

Java 中克隆的概念

在 OOP 中,复制对象意味着创建现有对象的克隆。有许多方法可以复制对象;其中两种是复制构造函数克隆。Java 中有两种克隆类型:

  • 浅克隆
  • 深克隆

深拷贝和浅拷贝都是对象克隆的类型。当我们谈论一个对象时,我们将其视为一个不能进一步分解的单一单元。

假设我们有一个 Student 对象。Student 对象包含其他对象,如下图所示。Student 对象包含 Name 和 Address 对象。Name 包含 FirstName 和 LastName 对象,Address 对象由 Street 和 city 对象组成。当我们谈论 Student 时,我们谈论的是整个对象网络。

How many Ways to Create an Object in Java

当我们想要修改或移动对象但仍保留原始对象时,就会创建对象的克隆。

浅克隆

  • 当我们使用 clone() 方法的默认实现时,Java 会使用浅克隆。
  • 对象的浅克隆会创建一个主对象的克隆,但不会复制内部对象。
  • 内部对象在原始对象及其副本之间共享。

例如,如果我们想创建一个 Student 的浅拷贝,我们应该创建一个 Student 的第二个对象。但是两个对象共享同一个 Name 和 Address。考虑以下示例:

浅拷贝的一个缺点是两个对象不独立。当我们修改一个 Student 的 Name 对象时,它也会修改其他 Student 对象。

在下面的示例中,我们有一个带有引用变量 mba 的 Student 对象;然后我们创建了 MBA 的副本,创建了一个第二个 Student 对象 mca。如果 mca 试图通过修改其 Address 对象来 moveOut(),则 mba 会随之移动。

这是因为 mba 和 mca 对象共享同一个 Address 对象。如果我们更改其中一个对象中的 Address,则两个对象都会被修改。

深克隆

  • 深克隆是对象的完全独立的副本。
  • 因此,对于深拷贝,我们需要确保所有成员类也实现 Cloneable 接口并覆盖 Object 类的 clone() 方法。

当我们修改一个 Student 对象的 Address 对象时,它不会修改另一个 Student 对象。在上面的代码中,我们可以看到我们不仅在 Student 对象上使用了复制构造函数,还在内部对象上也使用了复制构造函数。

要创建深克隆,我们需要不断复制所有 Student 对象嵌套的元素,直到只剩下原始类型和不可变类型。

Street 对象有两个实例变量 name 和 number。number 是一个原始整数值,不是对象。它不能被共享。当我们创建第二个实例变量时,我们会自动创建一个独立的副本。上面的代码中的 String 是一个不可变对象,即一旦创建,就永远无法更改。因此,我们可以共享它而无需对其进行深拷贝。


下一个主题Java 教程