Java深克隆和浅克隆的使用和区别

背景

Java中想要复制对象时,需要考虑到一个问题:如果是引用类型对象,如果只是通过一般的“=”赋值,那么因为只是把引用地址给了新对象,所以改变新对象时会因为实际改变的引用地址指向的对象,因此难免出现改变源对象的属性。例如:

public class Demo1 {
    static class People {
        private String name;
        private String age;

        public String getName() {
            return name;
        }

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

        public String getAge() {
            return age;
        }

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

        @Override
        public String toString() {
            return "People{" +
                    "name='" + name + '\'' +
                    ", age='" + age + '\'' +
                    '}';
        }
    }

    public static void main(String[] args) {
        People people1 = new People();
        people1.setName("zhangsan");
        people1.setAge("23");
        System.out.println("源对象:" + people1);
        People people2 = people1;
        System.out.println("新对象:" + people2);
        people2.setName("lisi");
        System.out.println("修改后的源对象:" + people1);
        System.out.println("修改后的新对象:" + people2);
    }
}

结果:

源对象:People{name='zhangsan', age='23'}
新对象:People{name='zhangsan', age='23'}
修改后的源对象:People{name='lisi', age='23'}
修改后的新对象:People{name='lisi', age='23'}

因此这时就需要考虑解决办法,如何把源对象的属性给新对象,而且两个对象改变属性时又可以不相互影响?

概念

Java复制对象的实现方式中有个“克隆”的概念,就是复制一个对象的副本,而克隆又分浅克隆和深克隆。

  • 浅克隆:克隆一个新对象,但是属性如果是引用类型对象则用的同一个引动地址指向的对象。
  • 深克隆:克隆一个新对象,包括引用类型的属性内存地址指向的也是新创建的对象。

实现步骤:

  • 实现Clonable接口;
  • 重写clone()方法。
  • 调用clone()方法克隆对象。

浅克隆

1、验证是否为新对象

bean(未重写toString(),用来验证克隆出的对象是否为新的)

public class People implements Cloneable {
    private String name;
    private int 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;
    }

    //修改权限为:public
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

main

    public static void main(String[] args) throws CloneNotSupportedException {
        People old = new People();
        old.setName("zhangsan");
        old.setAge(23);
        People clone = (People) old.clone();
        System.out.println("源对象:" + old);
        System.out.println("新对象:" + clone);
    }

结果:地址不同,所以clone的新对象和原来的不是同一个

源对象:com.company.bean.People@4554617c
新对象:com.company.bean.People@74a14482

 2、验证引用类型属性是否为新的

Car

public class Car implements Cloneable {
    private String name;
    private String color;

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

People

public class People implements Cloneable {
    private String name;
    private int age;
    private Car car;

    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;
    }

    public Car getCar() {
        return car;
    }

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

    //修改权限为:public
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}

main

    public static void main(String[] args) throws CloneNotSupportedException {
        People old = new People();
        old.setName("zhangsan");
        old.setAge(23);
        Car car = new Car();
        car.setName("ferrari");
        car.setColor("red");
        old.setCar(car);
        People clone = (People) old.clone();
        System.out.println("源对象:" + old);
        System.out.println("新对象:" + clone);
    }

结果:虽然对象是新的,但是clone的属性还是用一个。

源对象:People{name='zhangsan', age=23, car=com.company.bean.Car@4554617c}
新对象:People{name='zhangsan', age=23, car=com.company.bean.Car@4554617c}

深克隆:重写对象中引用类型属性clone()

Car

public class Car implements Cloneable {
    private String name;
    private String color;

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    //重写clone
    @Override
    public  Car clone() throws CloneNotSupportedException {
        return (Car) super.clone();
    }
}

People

public class People implements Cloneable {
    private String name;
    private int age;
    private Car car;

    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;
    }

    public Car getCar() {
        return car;
    }

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

    //重写clone方法
    @Override
    public People clone() throws CloneNotSupportedException {
        People people = (People) super.clone();
        people.car = car.clone();
        return people;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}

main

    public static void main(String[] args) throws CloneNotSupportedException {
        People old = new People();
        old.setName("zhangsan");
        old.setAge(23);
        Car car = new Car();
        car.setName("ferrari");
        car.setColor("red");
        old.setCar(car);
        People clone = (People) old.clone();
        System.out.println("源对象:" + old);
        System.out.println("新对象:" + clone);
    }

结果:引用类型属性也是新的

源对象:People{name='zhangsan', age=23, car=com.company.bean.Car@4554617c}
新对象:People{name='zhangsan', age=23, car=com.company.bean.Car@74a14482}

补充:序列化方式实现

Car

public class Car implements Serializable {
    private String name;
    private String color;

    public String getName() {
        return name;
    }

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

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

}

People

public class People implements Serializable {
    private String name;
    private int age;
    private Car car;

    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;
    }

    public Car getCar() {
        return car;
    }

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

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}

main

   public static void main(String[] args) throws IOException, ClassNotFoundException {
        People old = new People();
        old.setName("zhangsan");
        old.setAge(23);
        Car car = new Car();
        car.setName("ferrari");
        car.setColor("red");
        old.setCar(car);
        System.out.println("源对象:" + old);
        //序列化
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(outputStream);
        oos.writeObject(old);
        //反序列化
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(inputStream);
        People clone = (People) ois.readObject();
        System.out.println("新对象:" + clone);
    }

结果:和深克隆一样,对象和引用类型属性的地址都是新的。

源对象:People{name='zhangsan', age=23, car=com.company.bean.Car@4554617c}
新对象:People{name='zhangsan', age=23, car=com.company.bean.Car@2d98a335}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值