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,将构造器本身的异常抛出。