用Java创建对象的5种不同方式


作为Java开发人员,我们通常每天都会创建许多对象,但是我们总是使用新的或依赖项管理系统(例如Spring)来创建这些对象。但是,有更多方法可以创建本文中将要研究的对象。

用Java创建对象的共有5种核心方式,下面将以其示例加以说明,然后介绍创建对象的行的字节码。但是,有很多Apis可以为我们创建对象,但是这些Apis还将间接使用这5种核心方式之一,例如Spring BeanFactory。

5-different-ways-of-object-creation-in-java.jpg

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

Employee emp1 = new Employee();
0: new           #19          // class org/programming/mitra/exercises/Employee
 3: dup
 4: invokespecial #21          // Method org/programming/mitra/exercises/Employee."":()V

2.使用Class类的newInstance()方法 我们还可以使用Class类的newInstance()方法创建一个对象。此newInstance()方法调用no-arg构造函数来创建对象。

我们可以通过newInstance()通过以下方式创建对象:

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

或者

Employee emp2 = Employee.class.newInstance();
51: invokevirtual    #70    // Method java/lang/Class.newInstance:()Ljava/lang/Object;

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

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

111: invokevirtual  #80  // Method java/lang/reflect/Constructor.newInstance:([Ljava/lang/Object;)Ljava/lang/Object;

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

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

要在对象上使用clone()方法,我们需要实现Cloneable并在其中定义clone()方法。

Employee emp4 = (Employee) emp3.clone();
162: invokevirtual #87  // Method org/programming/mitra/exercises/Employee.clone ()Ljava/lang/Object;

Java克隆是Java社区中最有争议的话题,它的确有其缺点,但是在对象完全满足Java克隆的强制条件之前,它仍然是创建任何对象的副本的最流行和最简单的方法。我在长达3篇文章的 Java克隆系列中详细介绍了克隆,其中包括诸如Java克隆和克隆类型(浅和深)等文章,并带有示例,Java克隆-复制构造函数与克隆,Java克隆-甚至复制构造函数都不一样的细节。足够。如果您想了解更多有关克隆的信息,请继续阅读。

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

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

261: invokevirtual  #118   // Method java/io/ObjectInputStream.readObject:()Ljava/lang/Object;

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

我已经在讨论的序列化和反序列化的详细信息,系列化系列,其中包括像文章所有你需要知道Java序列,如何自定义序列化在Java中使用Externalizable接口,如何使用Java在内存系列化深克隆对象。如果您想了解更多有关序列化的信息,请继续阅读。

例子: 让我们考虑一个我们要为其创建对象的Employee类:

class Employee implements Cloneable, Serializable {

    private static final long serialVersionUID = 1L;

    private String name;

    public Employee() { System.out.println("Employee Constructor Called..."); }

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() { return Objects.hash(name); }

    @Override
    public String toString() { return String.format("Employee{name='%s'}", name); }

    @Override
    public Object clone() {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return obj;
    }
}

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

public class ObjectCreation {
    public static void main(String... args) throws Exception {

        // 1. Using new keyword
        Employee emp1 = new Employee();
        emp1.setName("emp1");


        // 2. Using Class class's newInstance() method
        Employee emp2 = Employee.class.newInstance();
        emp2.setName("emp2");


        // 3. Using Constructor class's newInstance() method
        Constructor<Employee> constructor = Employee.class.getConstructor();
        Employee emp3 = constructor.newInstance();
        emp3.setName("emp3");

        // 4. Using clone() method
        Employee emp4 = (Employee) emp3.clone();
        emp4.setName("emp4");


        // Serialization
        try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.obj"))) {
            out.writeObject(emp4);
        }

        // 5. Using Deserialization
        Employee emp5;
        try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"))) {
            emp5 = (Employee) in.readObject();
            emp5.setName("emp5");
        }

        System.out.println(emp1 + ", hashcode : " + emp1.hashCode());
        System.out.println(emp2 + ", hashcode : " + emp2.hashCode());
        System.out.println(emp3 + ", hashcode : " + emp3.hashCode());
        System.out.println(emp4 + ", hashcode : " + emp4.hashCode());
        System.out.println(emp5 + ", hashcode : " + emp5.hashCode());
    }

该程序将给出以下输出:

Employee Constructor Called...
Employee Constructor Called...
Employee Constructor Called...
Employee{name='emp1'}, hashcode : 3117192
Employee{name='emp2'}, hashcode : 3117193
Employee{name='emp3'}, hashcode : 3117194
Employee{name='emp4'}, hashcode : 3117195
Employee{name='emp5'}, hashcode : 3117196

您可以在此Github存储库中找到本文的完整源代码,请随时提供宝贵的反馈。


原文链接:http://codingdict.com