对象克隆

发布时间 2023-03-27 13:25:14作者: 大意了没有闪

直接赋值

public class ObjectClone {
    public static void main(String[] args) {
        Person p1 = new Person("张三", 25);
        Person p2 = p1;

        // 修改p2会影响到p1
        p2.age = 30;
        p2.name = "李四";
        System.out.println(p1);
    }
}

@Data
@AllArgsConstructor
class Person {
    String name;
    int age;
}

// 输出:Person(name=李四, age=30)

实现Cloneable接口

  1. 实现Cloneable接口
  2. 重写Object类的clone()方法
public class ObjectClone {
    public static void main(String[] args) {
        Person p1 = new Person("张三", 25);
        Person p2 = p1.clone();

        // 修改p2不会影响到p1
        p2.age = 30;
        p2.name = "李四";
        System.out.println(p1);
        System.out.println(p2);
    }
}

@Data
@AllArgsConstructor
class Person implements Cloneable {
    String name;
    int age;

    @Override
    protected Person clone() {
        Person person = null;
        try {
            person = (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return person;
    }
}

// 输出:
Person(name=张三, age=25)
Person(name=李四, age=30)

带引用类型的克隆

给Person类增加引用类型,然后拷贝并修改这个引用类型的值

public class ObjectClone {
    public static void main(String[] args) {
        Person p1 = new Person("张三", 25);
        p1.setPartner(new Person("小红", 22));
        Person p2 = p1.clone();

        // 修改p2的partner会影响到p1
        p2.age = 30;
        p2.name = "李四";
        p2.getPartner().setName("Mary");
        p2.getPartner().setAge(18);
        System.out.println(p1);
        System.out.println(p2);
    }
}

@Data
class Person implements Cloneable {
    String name;
    int age;
    Person partner;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Person clone() {
        Person person = null;
        try {
            person = (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return person;
    }
}

// 输出,发现两个partner变成一样的了
Person(name=张三, age=25, partner=Person(name=Mary, age=18, partner=null))
Person(name=李四, age=30, partner=Person(name=Mary, age=18, partner=null))

// 如果需要对引用类型也单独复制一份,需要再次调用clone()方法
@Override
protected Person clone() {
    Person person = null;
    try {
        person = (Person) super.clone();
        if (partner != null) {
            person.partner = partner.clone();
        }
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    return person;
}

// 输出:
Person(name=张三, age=25, partner=Person(name=小红, age=22, partner=null))
Person(name=李四, age=30, partner=Person(name=Mary, age=18, partner=null))

使用工具类

cn.hutool.core.util.clone(T obj)
克隆对象
如果对象实现Cloneable接口,调用其clone方法
如果实现Serializable接口,执行深度克隆
否则返回null

实现Cloneable,需要自己实现clone()方法,项目维护时,如果增加了引用字段,也很容易忘记去修改clone()方法,所以实现Serializable接口,执行深度克隆的方法比较好

public class ObjectClone {
    public static void main(String[] args) {
        Person p1 = new Person("张三", 25);
        p1.setPartner(new Person("小红", 22));
        Person p2 = ObjectUtil.clone(p1);

        // 修改p2的partner不会影响到p1
        p2.age = 30;
        p2.name = "李四";
        p2.getPartner().setName("Mary");
        p2.getPartner().setAge(18);
        System.out.println(p1);
        System.out.println(p2);
    }
}

@Data
class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    String name;
    int age;
    Person partner;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
// 结果
Person(name=张三, age=25, partner=Person(name=小红, age=22, partner=null))
Person(name=李四, age=30, partner=Person(name=Mary, age=18, partner=null))