在 Java 中创建对象有哪些不同的方法?

前几天我和一个同事谈过这件事。

使用构造函数是显而易见的,但是还有什么其他的方法呢?

440853 次浏览

反思:

someClass.newInstance();

这完全取决于你所说的创建是什么意思,但其他一些是:

  • 克隆法
  • 荒漠化
  • 反射(Class.newInstance ())
  • 反射(构造函数对象)

在 Java 语言中,创建对象的唯一方法是调用其构造函数,无论是显式的还是隐式的。使用反射导致对构造函数方法的调用,反序列化使用反射调用构造函数,工厂方法包装对构造函数的调用以抽象实际的构造函数,克隆类似于包装的构造函数调用。

从 API 用户的角度来看,构造函数的另一种替代方法是静态工厂方法(比如 BigInteger.valueOf ()) ,尽管对于 API 作者(技术上是“真实的”)来说,对象仍然是使用构造函数创建的。

还有 ClassLoader.loadClass (string) ,但不常用。

如果你想成为一个完全的律师关于它,数组是 严格来说对象,因为数组的。长度属性。所以初始化数组会创建一个对象。

是的,您可以使用反射创建对象。例如,String.class.newInstance()将为您提供一个新的空 String 对象。

你也可以用

 Object myObj = Class.forName("your.cClass").newInstance();

反射也会为你做这项工作。

SomeClass anObj = SomeClass.class.newInstance();

是创建类的新实例的另一种方法。在这种情况下,您还需要处理可能引发的异常。

如果你是 Java 新手,应该注意到这一点,每个对象都是从 Object 继承来的

受保护的本机对象克隆()抛出 CloneNotSupportedException;

此外,您可以将 反序列化数据放入一个对象中!


更新 : 谢谢汤姆在你的评论中指出这一点! 迈克尔也进行了实验。

它将遍历派生最多的不可序列化超类的构造函数。
如果该类没有 no-args 构造函数,则在反序列化时引发 InvalidClassException。

请看汤姆对所有病例的完整治疗的回答; -)
有没有其他方法可以不使用 java 中的“ new”关键字来创建对象

还可以克隆现有对象(如果它实现了 Cloneable)。

Foo fooClone = fooOriginal.clone ();

方法有很多:

  • 通过 Class.newInstance
  • 通过 Constructor.newInstance
  • 通过反序列化(使用派生最多的非序列化基类的 no-args 构造函数)。
  • 透过 Object.clone(不调用构造函数)。
  • 通过 JNI (应该调用构造函数)。
  • 通过为您调用 new的任何其他方法。
  • 我想您可以将类加载描述为创建新对象(例如实际存在的 String)。
  • 作为声明中初始化的一部分的文字数组(数组没有构造函数)。
  • “ varargs”(...)方法调用中的数组(数组没有构造函数)。
  • 非编译时间常量字符串串联(在一个典型的实现上,碰巧至少生成四个对象)。
  • 导致运行库创建和引发异常。例如 throw null;"".toCharArray()[0]
  • 哦,当然还有原始人的拳击(除非缓存)。
  • JDK8应该有 lambdas (本质上是简洁的匿名内部类) ,它们被隐式地转换为对象。
  • 为了完整性(和 Pa lo Ebermann) ,new关键字也有一些语法。
  • 使用 new操作符(从而调用构造函数)
  • 使用反射 clazz.newInstance()(它再次调用构造函数)。或者通过 clazz.getConstructor(..).newInstance(..)(同样使用构造函数,但是您可以选择使用哪个构造函数)

通过调用对象类的构造函数来总结答案(一种主要方法)。

更新: 另一个答案列出了两种不涉及使用构造函数的方法——反序列化和克隆。

在 Java 中创建对象有四种不同的方法:

使用 new关键字
这是在 Java 中创建对象的最常用方法。几乎99% 的对象都是以这种方式创建的。

 MyObject object = new MyObject();

使用 Class.forName()
如果我们知道这个类的名字,如果它有一个公共缺省构造函数,我们就可以用这种方式创建一个对象。

MyObject object = (MyObject) Class.forName("subin.rnd.MyObject").newInstance();

C . 使用 clone()
克隆()可用于创建现有对象的副本。

MyObject anotherObject = new MyObject();
MyObject object = (MyObject) anotherObject.clone();

使用 object deserialization
对象反序列化就是从序列化形式创建对象。

ObjectInputStream inStream = new ObjectInputStream(anInputStream );
MyObject object = (MyObject) inStream.readObject();

你可以从 给你上读出来。

有一种类型的对象不能通过普通的实例创建机制(调用构造函数)构造: 阵列。创建数组时使用

 A[] array = new A[len];

或者

 A[] array = new A[] { value0, value1, value2 };

正如 Sean 在评论中所说,这在语法上类似于构造函数调用,在内部,它只不过是一个内存块的分配和零初始化(或者用显式内容进行初始化,在第二种情况下) ,一些头部指示类型和长度。

当向 varargs-method 传递参数时,也会隐式地创建(并填充)一个数组。

第四种方法是

 A[] array = (A[]) Array.newInstance(A.class, len);

当然,克隆和反序列化在这里也是可行的。

在标准 API 中有许多创建数组的方法,但实际上它们都在使用其中的一种(或多种)方法。

其他方法,如果我们要详尽无遗。

  • 在 Oracle JVM 上是 Unsafe.allocateInstance () ,它在不调用构造函数的情况下创建一个实例。
  • 使用字节码操作,您可以向 anewarraymultianewarraynewarraynew添加代码。可以使用 ASM 或 BCEL 等库添加这些内容。Oracle 的 Java 附带了一个 bcel 版本。同样,这不会调用构造函数,但是您可以将构造函数作为单独的调用来调用。

在 Java 中创建对象有五种不同的方法:

1. 使用‘ new’关键字:

这是在 Java 中创建对象的最常用方法。几乎99% 的对象都是以这种方式创建的。

MyObject object = new MyObject();//normal way

2. 使用工厂法:

ClassName ObgRef=ClassName.FactoryMethod();

例如:

RunTime rt=Runtime.getRunTime();//Static Factory Method

3. 使用克隆概念:

通过使用 clone(),可以使用 clone()创建现有对象的副本。

MyObjectName anotherObject = new MyObjectName();
MyObjectName object = anotherObjectName.clone();//cloning Object

4. 使用‘ Class.forName ()’:

如果我们知道这个类的名字,如果它有一个公共缺省构造函数,我们就可以用这种方式创建一个对象。

MyObjectName object = (MyObjectNmae) Class.forName("PackageName.ClassName").newInstance();

例如:

String st=(String)Class.forName("java.lang.String").newInstance();

5. 使用对象反序列化:

对象反序列化就是从序列化形式创建对象。

ObjectInputStreamName inStream = new ObjectInputStreamName(anInputStream );
MyObjectName object = (MyObjectNmae) inStream.readObject();

我们可以用5种方法创建一个对象:

  1. 由新的操作员操作
  2. 通过反射(例如 Class.forName ()后跟 Class.newInstance ())
  3. 按工厂方法
  4. 通过克隆
  5. 通过反射 api

我们也可以这样创建对象:-

String s ="Hello";

没人讨论过。

方法1

使用新的关键字。这是在 Java 中创建对象的最常用方法。几乎99% 的对象都是以这种方式创建的。

Employee object = new Employee();

方法2

使用 Class.forName ()。ForName ()为您提供类对象,这对于反射非常有用。这个对象的方法是由 Java 定义的,而不是由编写类的程序员定义的。每个班级都是一样的。调用 newInstance () ,为您提供该类的一个实例(即调用 Class.forName (“ ExampleClass”))。NewInstance ()等效于调用 new ExampleClass () ,在这个函数上可以调用类定义的方法,访问可见字段等等。

Employee object2 = (Employee) Class.forName(NewEmployee).newInstance();

ForName ()将始终使用调用方的 ClassLoader,而 ClassLoader.loadClass ()可以指定不同的 ClassLoader。我相信 Class.forName 也会初始化加载的类,而 ClassLoader.loadClass ()方法不会马上这样做(直到第一次使用它才会初始化)。

另一条必读:

Java: 线程状态示例介绍 简单的 Java 枚举示例

方法3

使用 clone ()。 clone ()可以用来创建现有对象的副本。

Employee secondObject = new Employee();
Employee object3 = (Employee) secondObject.clone();

方法4

使用 newInstance ()方法

Object object4 = Employee.class.getClassLoader().loadClass(NewEmployee).newInstance();

方法5

使用对象反序列化。对象反序列化不过是从序列化形式创建对象。

// Create Object5
// create a new file with an ObjectOutputStream
FileOutputStream out = new FileOutputStream("");
ObjectOutputStream oout = new ObjectOutputStream(out);


// write something in the file
oout.writeObject(object3);
oout.flush();


// create an ObjectInputStream for the file we created before
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("crunchify.txt"));
Employee object5 = (Employee) ois.readObject();

在 Java 中创建对象有五种不同的方法,

1. 使用 new关键字 →构造函数进行调用

Employee emp1 = new Employee();

2. 使用 Class →构造函数的 newInstance()方法调用

Employee emp2 = (Employee) Class.forName("org.programming.mitra.exercises.Employee")
.newInstance();

它也可以写成

Employee emp2 = Employee.class.newInstance();

3. 使用 Constructor →构造函数的 newInstance()方法调用

Constructor<Employee> constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance();

4. 使用 clone()方法 →无构造函数调用

Employee emp4 = (Employee) emp3.clone();

5. 使用反序列化 →无构造函数调用

ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp5 = (Employee) in.readObject();

前三个方法 new关键字和两个 newInstance()都包含一个构造函数调用,但后来两个克隆和反序列化方法创建对象时不调用构造函数。

以上所有的方法都有不同的字节码与它们相关联,阅读 用示例创建 Java 对象的不同方法的例子和更详细的描述,例如所有这些方法的字节码转换。

然而,人们可能会争辩说,创建一个数组或字符串对象也是创建对象的一种方式,但是这些事情只对一些类有特定性,并且由 JVM 直接处理,而我们可以通过使用这5种方式来创建任何类的对象。