Java創建對象的五種方式

 閱讀大約需要1分鐘

Java創建對象的五種方式

本文將介紹五種方式來創建一個Java對象:

  • 使用new關鍵字
  • 使用Class.newInstance
  • 使用Constructor.newInstance
  • 使用clone方法
  • 使用反序列化

創建一個對象Student

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Student implements Cloneable, Serializable {

    @Override
    public Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }

    private String name;
    private int age;
}
1.通過new關鍵字創建

通過這種方式可以調用任意的構造器(無參的和有參的)

Student student = Student.builder().name("john").age(18).build();
log.info("get student>>>" + student);
Student student1=new Student();
student1.setAge(18);
student1.setName("john1");
log.info("get student>>>" + student1);
2.Class.newInstance

Class類的newInstance使用的是類的public的無參構造方法, 因此使用此方法創建對象的前提是必須有public的無參構造器才行。 還可以用Class.forName()來動態獲取一個類的Class對象

try {
    Student student2 = Student.class.newInstance();
    student2.setName("john2");
    student2.setAge(18);
    log.info("get student2>>>" + student2);
    Class<?> clazz= Class.forName("com.example.demo.entity.Student");
    Student student3= (Student) clazz.newInstance();
    student3.setName("Hello");
    student3.setAge(19);
    log.info("get student3>>>" + student3);
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
    e.printStackTrace();
}
3.構造一個對象(反射)

java.lang.reflect.Constructor類裡有一個newInstance方法可以創建對象, 可以通過這個newInstance方法調用有參數(不再必須是無參)的和私有的構造函數(不再必須是public)。

try {
    Constructor<Student> constructor = Student.class.getConstructor();
    Student student4 = constructor.newInstance();
    student4.setAge(18);
    student4.setName("john");
    log.info("get student4>>>" + student4);

    Constructor<Student> constructor1 = Student.class.getConstructor(String.class, int.class);
    Student student5 = constructor1.newInstance("smith", 19);
    log.info("get student5>>>" + student5);
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
    e.printStackTrace();
}
4.克隆一個對象

無論何時我們調用一個對象的clone方法,JVM都會創建一個新的對象,將前面的對象的內容全部拷貝進去,用clone方法創建對象並不會調用任何構造函數。 要使用clone方法,我們必須先實現Cloneable接口並覆寫Object的clone方法,因為Object的這個方法是protected的,若不覆寫,外部調用不了。

try {
    Student student6=student.clone();
    log.info("get student6>>>" + student6);
    log.info(String.valueOf(student==student6));
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}
5.反序列化

當我們序列化和反序列化一個對象時,JVM會給創建一個單獨的對象。 在反序列化時,JVM創建對象並不會調用任何構造函數。 為了反序列化一個對象,需要讓Student類實現Serializable接口。

try {
    ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("data.obj"));
    objectOutputStream.writeObject(new Student("john",19));
    objectOutputStream.close();

    ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("data.obj"));
    Student student7= (Student) inputStream.readObject();
    inputStream.close();
    log.info("get student7>>>" + student7);
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}
關於兩種newInstance方法的區別?

Class類位於java的lang包中,而Constructor是java反射機制的一部分

Class類的newInstance只能觸發無參數的構造方法創建對象,而Constructor類的newInstance能觸發有參數或者任意參數的構造方法來創建對象。

Class類的newInstance需要其構造方法是public的或者對調用方法可見的,而Constructor類的newInstance可以在特定環境下調用私有構造方法來創建對象。

Class類的newInstance拋出類構造函數的異常,而Constructor類的newInstance包裝了一個InvocationTargetException異常。

Class類本質上調用了反射包Constructor中無參數的newInstance方法,捕獲了InvocationTargetException,將構造器本身的異常拋出。