不通过构造函数也能创建对象吗?
答:Java创建对象的几种方式(重要):1)、用new语句创建对象,这是最常见的创建对象的方法。
2)、运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
3)、调用对象的clone()方法。
4)、运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。(1)和(2)都会明确的显式的调用构造函数 ;
(3)是在内存上对已有对象的影印,所以不会调用构造函数 ;
(4)是从文件中还原类的对象,也不会调用构造函数
1、实现Cloneable接口并重写Object类中的clone()方法
public class MyUtil {
private MyUtil() {
throw new AssertionError();
}
public static <T> T clone(T obj) throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bout);
oos.writeObject(obj);
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin);
return (T) ois.readObject();
// 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义
// 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源
}
}
方法调用如下所示
Person p2 = MyUtil.clone(p1); // 深度克隆
具体实例如下:
人的属性
@Data
class Person implements Serializable {
private static final long serialVersionUID = -9102017020286042305L;
private String name; // 姓名
private int age; // 年龄
private Car car; // 座驾
public Person(String name, int age, Car car) {
this.name = name;
this.age = age;
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
}
小汽车类
@Data
class Car implements Serializable {
private static final long serialVersionUID = -5713945027627603702L;
private String brand; // 品牌
private int maxSpeed; // 最高时速
public Car(String brand, int maxSpeed) {
this.brand = brand;
this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
}
}
方法调用
class CloneTest {
public static void main(String[] args) {
try {
Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300));
Person p2 = MyUtil.clone(p1); // 深度克隆
p2.getCar().setBrand("BYD");
// 修改克隆的Person对象p2关联的汽车对象的品牌属性
// 原来的Person对象p1关联的汽车不会受到任何影响
// 因为在克隆Person对象时其关联的汽车对象也被克隆了
System.out.println(p1);
System.out.println(p2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果如下:
Person [name=Hao LUO, age=33, car=Car [brand=Benz, maxSpeed=300]]
Person [name=Hao LUO, age=33, car=Car [brand=BYD, maxSpeed=300]]
2、通过反序列化实现
import java.io.*;
public class BeanUtil {
@SuppressWarnings("unchecked")
public static <T> T cloneTo(T src) throws RuntimeException {
ByteArrayOutputStream memoryBuffer = new ByteArrayOutputStream();
ObjectOutputStream out = null;
ObjectInputStream in = null;
T dist = null;
try {
out = new ObjectOutputStream(memoryBuffer);
out.writeObject(src);
out.flush();
in = new ObjectInputStream(new ByteArrayInputStream(
memoryBuffer.toByteArray()));
dist = (T) in.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (out != null)
try {
out.close();
out = null;
} catch (IOException e) {
throw new RuntimeException(e);
}
if (in != null)
try {
in.close();
in = null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return dist;
}
}
相关的单元测试代码
public static void main(String[] args) {
try {
Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300));
// 2、反序列化生成对象
Person p3 = BeanUtil.cloneTo(p1);
p3.getCar().setBrand("L");
p3.getCar().setMaxSpeed(400);
System.out.println(p3);
} catch (Exception e) {
e.printStackTrace();
}
}
运行结果如下:
Person [name=Hao LUO, age=33, car=Car [brand=L, maxSpeed=400]]