方法一:new关键字(常用),可任意调用构造器(有参和无参)
public class Person1 {
private String name;
private int age;
public Person1() {
}
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person1 person1 = (Person1) o;
return age == person1.age && Objects.equals(name, person1.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person1{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
class Main1{
public static void main(String[] args) {
Person1 p1 = new Person1();
Person1 p2 = new Person1("lzj", 18);
}
}
方法二:通过反射创建对象:Class.newInstance()
前提:必须有public的无参构造器!!!
class Main2{
public static void main(String[] args) throws Exception {
Person2 person2 = Person2.class.newInstance();
System.out.println(person2);
}
}
方法三:通过构造器:Constructor.newInstance()
通过Constructor类中的newInstance创建,此方法调用有参和私有的构造函数(不必须是public)
class Main3{
public static void main(String[] args) throws Exception {
// 返回public、非public、private
Constructor<?>[] declaredConstructors = Person3.class.getDeclaredConstructors();
// 只返回public
Constructor<?>[] constructor = Person3.class.getConstructors();
Constructor<?> noArgsConstructor = declaredConstructors[0];
Constructor<?> haveArgsConstructor = declaredConstructors[1];
// 非public的构造,必须设置true才能用于创建实例
noArgsConstructor.setAccessible(true);
Object p1 = noArgsConstructor.newInstance();
Object p2 = haveArgsConstructor.newInstance("lzj", 18);
System.out.println(p1);
System.out.println(p2);
System.out.println(p1==p2);
}
}
方法四:通过调用对象的clone()方法,JVM会创建一个新对象,将之前对象的内容拷贝进去。
前提:实现Cloneable接口中的clone方法(因为这个方法是protected,不重写,外部无法调用)
public class Person4 implements Cloneable{
private String name;
private int age;
// 重写clone方法
@Override
protected Person4 clone() throws CloneNotSupportedException {
return (Person4)super.clone();
}
}
class Main4{
public static void main(String[] args) throws CloneNotSupportedException {
Person4 person = new Person4("lzj",18);
Object clone = person.clone();
System.out.println(person);
System.out.println(clone);
// == 此时是引用数据类型,比较对象内存地址是否相同
System.out.println(person == clone); //false
}
}
方法五:通过序列化和反序列化一个对象,JVM会创建一个单独的对象,反序列化时不会调用任何构造函数。
通过序列化和反序列化一个对象,JVM会创建一个单独的对象,反序列化时不会调用任何构造函数。 前提:需要实现 Serializable 接口 备注:序列和反序列化,特别耗内存
public class Person5 implements Serializable {
private String name;
private int age;
}
class Main5{
public static void main(String[] args) throws Exception {
Person5 p = new Person5("lzj", 18);
String serializeObj = SerializationUtils.serialize(p);// 序列化
System.out.println(serializeObj);
Person5 obj = (Person5)SerializationUtils.deserialize(serializeObj);// 反序列化
System.out.println(obj);
// ¬í sr JavaBean.Person5)»,ïD-« I ageL namet Ljava/lang/String;xp t lzj
// Person5{name='lzj', age=18}
}
}
封装一个 “序列化和反序列化” 工具类
// 封装成静态方法(序列化、反序列化)
public class SerializationUtils {
static String path = "data";
static public String serialize(Object obj) throws Exception {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
// 序列化对象
oos.writeObject(obj);
String s = bos.toString("ISO-8859-1");
return s;
}
static public Object deserialize(String str) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes("ISO-8859-1"));
ObjectInputStream ois = new ObjectInputStream(bis);
// 反序列化
return ois.readObject();
}
}
附加两道衍生面试题:
题一:Java创建实例对象,是否必须要通过构造函数?
创建对象的方式 | 是否调用了构造器 |
new关键字 | 是 |
Class.newInstance() | 是 |
Constructor.newInstance() | 是 |
clone() | 否 |
反序列化 | 否 |
答:Java创建实例对象,并不一定必须调用构造器。
还有一个库 Objenesis
,它也能不使用构造器来创建一个实例。
Spring的 ObjenesisCglibAopProxy
就是依赖于Objenesis
这个库的~
题二:关于两种newInstance方法的区别?
1、Class类位于java.lang包下,Constructor是java反射机制的一部分。
2、Class类的newInstance触发 无参构造方法 ,Constructor类的newInstance触发 有参或任意参数的构造方法 。
3、Class类的newInstance的构造方法需要 public可见 ,Constructor类的newInstance的构造方法需要调用私有构造时设置 noArgsConstructor.setAccessible(true);
4、Class类的newInstance 抛出类构造函数异常 ,Constructor类的newInstance InvocationTargetException 异常 。