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