Java
作为Java开发人员,通常每天都会创建许多对象,但是总是使用新的或依赖管理系统(例如Spring)来创建这些对象。但是还有更多方法可以创建对象。
用Java创建对象的共有5种核心方式,下面将以其示例加以说明,然后介绍创建对象的行的字节码。但是,有很多API可以创建对象,但是这些API还将间接使用这5种核心方式之一,例如Spring BeanFactory。
五种创建Java对象的方法 - 图1
如果将执行最后给出的程序,则会看到方法1、2、3使用构造函数创建对象,而4、5没有调用构造函数创建对象。

1、使用新关键字

这是创建对象的最常见和常规的方法,也是一种非常简单的方法。通过使用此方法,可以调用要调用的任何构造函数(无参数的构造函数和参数化的)。

  1. Employee emp1 = new Employee();

2、使用Class类的newInstance()方法

还可以使用Class类的newInstance()方法创建一个对象。此newInstance()方法调用no-arg构造函数来创建对象。
可以通过newInstance()通过以下方式创建对象:

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

Or

  1. Employee emp2 = Employee.class.newInstance();

3、使用构造方法类的newInstance()方法

Class类的newInstance()方法类似,java.lang.reflect.Constructor类中有一个newInstance()方法可用于创建对象。还可以使用此newInstance()方法来调用参数化构造函数和私有构造函数。

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

这两种newInstance()方法都被称为创建对象的反射方式。实际上,Class类的newInstance()方法在内部使用了Constructor类的newInstance()方法。这就是为什么最好使用后一种方法,并且也将其用于诸如Spring,Hibernate,Struts等不同框架的原因。要了解这两种newInstance()方法之间的区别,请阅读使用Example在Java中通过Reflection创建对象。

4、使用clone()方法:

每当在任何对象上调用clone()时,JVM实际上都会创建一个新对象,并将先前对象的所有内容复制到其中。使用clone方法创建对象不会调用任何构造函数。
要在对象上使用clone()方法,需要实现Cloneable并在其中定义clone()方法。

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

Java克隆是Java社区中最值得探讨的话题,它的确有其缺点,但是在对象完全满足Java克隆的强制条件之前,它仍然是创建任何对象的副本的最流行和最简单的方法。

5、使用反序列化

每当序列化然后反序列化一个对象时, JVM就会创建一个单独的对象。在反序列化中,JVM不使用任何构造函数来创建对象。要反序列化对象,需要在类中实现Serializable接口。

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

正如在上面的字节码中看到的那样,所有四个方法调用都转换为invokevirtual(这些方法直接处理对象的创建),除了第一个转换为两个调用的方法是一个是新的,另一个是调用特殊的(对构造函数的调用)。
例:考虑一个要为其创建对象的Employee类:

  1. class Employee implements Cloneable, Serializable {
  2. private static final long serialVersionUID = 1L;
  3. private String name;
  4. public Employee() { System.out.println("Employee Constructor Called..."); }
  5. public String getName() { return name; }
  6. public void setName(String name) { this.name = name; }
  7. @Override
  8. public boolean equals(Object o) {
  9. if (this == o) return true;
  10. if (o == null || getClass() != o.getClass()) return false;
  11. Employee employee = (Employee) o;
  12. return Objects.equals(name, employee.name);
  13. }
  14. @Override
  15. public int hashCode() { return Objects.hash(name); }
  16. @Override
  17. public String toString() { return String.format("Employee{name='%s'}", name); }
  18. @Override
  19. public Object clone() {
  20. Object obj = null;
  21. try {
  22. obj = super.clone();
  23. } catch (CloneNotSupportedException e) {
  24. e.printStackTrace();
  25. }
  26. return obj;
  27. }
  28. }

在下面的Java程序中,将以所有5种方式创建Employee对象。

  1. public class ObjectCreation {
  2. public static void main(String... args) throws Exception {
  3. // 1. Using new keyword
  4. Employee emp1 = new Employee();
  5. emp1.setName("emp1");
  6. // 2. Using Class class's newInstance() method
  7. Employee emp2 = Employee.class.newInstance();
  8. emp2.setName("emp2");
  9. // 3. Using Constructor class's newInstance() method
  10. Constructor<Employee> constructor = Employee.class.getConstructor();
  11. Employee emp3 = constructor.newInstance();
  12. emp3.setName("emp3");
  13. // 4. Using clone() method
  14. Employee emp4 = (Employee) emp3.clone();
  15. emp4.setName("emp4");
  16. // Serialization
  17. try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.obj"))) {
  18. out.writeObject(emp4);
  19. }
  20. // 5. Using Deserialization
  21. Employee emp5;
  22. try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"))) {
  23. emp5 = (Employee) in.readObject();
  24. emp5.setName("emp5");
  25. }
  26. System.out.println(emp1 + ", hashcode : " + emp1.hashCode());
  27. System.out.println(emp2 + ", hashcode : " + emp2.hashCode());
  28. System.out.println(emp3 + ", hashcode : " + emp3.hashCode());
  29. System.out.println(emp4 + ", hashcode : " + emp4.hashCode());
  30. System.out.println(emp5 + ", hashcode : " + emp5.hashCode());
  31. }
  32. }

该程序将给出以下输出:

  1. Employee Constructor Called...
  2. Employee Constructor Called...
  3. Employee Constructor Called...
  4. Employee{name='emp1'}, hashcode : 3117192
  5. Employee{name='emp2'}, hashcode : 3117193
  6. Employee{name='emp3'}, hashcode : 3117194
  7. Employee{name='emp4'}, hashcode : 3117195
  8. Employee{name='emp5'}, hashcode : 3117196