实现对象克隆的两种方式

1、实现 Cloneable 接口并重写 Object 类中的 clone()方法

2、 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,实现代码如下:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * @Auther: luojinxue
 * @Date: 2019/3/6 17:11
 * @Description: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 方法没有任何意义,这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,这一点不同于对外部资源(如文件流)的释放

下面是测试代码:

import java.io.Serializable;

/**
 * @Auther: luojinxue
 * @Date: 2019/3/6 17:29
 * @Description:人类
 */
public class Person implements Serializable {
    private static final long serialVersionUID = -5892238186685354739L;
    private String name;
    private Integer age;
    private Car car;

    public Person(String name, Integer age, Car car) {
        this.name = name;
        this.age = age;
        this.car = car;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}
import java.io.Serializable;

/**
 * @Auther: luojinxue
 * @Date: 2019/3/6 17:23
 * @Description:小轿车
 */
public class Car implements Serializable {
    private static final long serialVersionUID = -1121347856103926459L;
    private String brand; // 品牌
    private int maxSpeed; // 最高时速

    public Car(String brand, int maxSpeed) {
        this.brand = brand;
        this.maxSpeed = maxSpeed;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", maxSpeed=" + maxSpeed +
                '}';
    }
}
/**
 * @Auther: luojinxue
 * @Date: 2019/3/6 17:32
 * @Description:深度克隆测试
 */
public class CloneTest {
    public static void main(String[] args) {
        try {
            Person p1 = new Person("luo",27,new Car("迈巴赫",500));
            Person p2 = MyUtil.clone(p1);
            p2.getCar().setBrand("BYD");

            System.out.println(p1);
            System.out.println(p2);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

调试结果:

注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用 Object 类的 clone 方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行

猜你喜欢

转载自blog.csdn.net/luojinxue/article/details/88305698
今日推荐