为什么要使用克隆?如何实现对象克隆?深拷贝和浅拷贝区别是什么?

目录

一、什么是Java克隆

二、如何实现对象克隆

三、深拷贝和浅拷贝区别是什么


一、什么是Java克隆

Java中的克隆是指创建一个对象的副本,包括所有属性和方法。使用克隆可以避免修改原始对象的副作用,同时可以在多线程环境下保证数据独立性。

Java中的克隆分为浅克隆和深克隆两种方式。浅克隆只复制对象本身,而不复制对象引用的其他对象;而深克隆则将对象及其引用的其他对象都复制一份。

下面是一个实现浅克隆的示例代码:

public class Person implements Cloneable {
    private String name;
    private int age;

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

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

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person("John", 20);
        Person p2 = (Person) p1.clone(); // 克隆p1得到p2

        p2.setName("Jane");
        p2.setAge(22);

        System.out.println("p1 name: " + p1.getName() + ", age: " + p1.getAge());
        System.out.println("p2 name: " + p2.getName() + ", age: " + p2.getAge());
    }
}

在这个示例中,我们定义了一个Person类,并实现了Cloneable接口,重写了clone()方法以支持克隆。在main()方法中,我们创建了一个Person对象p1,并通过调用clone()方法得到了一个新的Person对象p2。然后修改了p2的name和age属性,并输出了两个对象的属性值。

需要注意的是,在进行克隆操作时,被克隆的对象必须实现Cloneable接口并重写clone()方法,且clone()方法必须抛出CloneNotSupportedException异常。而且,浅克隆只能复制对象本身的属性,对于引用类型的属性,只是复制了引用,而没有复制对象本身。如果需要实现深克隆,则需要自行实现复制引用对象的代码�

二、如何实现对象克隆

在Java中,要实现对象克隆可以使用两种方式:浅克隆和深克隆。浅克隆只复制对象本身,而不复制对象持有的引用对象;深克隆则复制整个对象,包括对象持有的引用对象。

下面是一个使用Object类提供的clone()方法实现浅克隆的示例代码:

public class ShallowCloneExample implements Cloneable {
    private String name;
    private int age;
    private Address address;

    public ShallowCloneExample(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    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 Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Address addr = new Address("China", "Beijing");
        ShallowCloneExample original = new ShallowCloneExample("Tom", 20, addr);
        ShallowCloneExample cloned = (ShallowCloneExample) original.clone();

        System.out.println("原始对象:" + original);
        System.out.println("克隆对象:" + cloned);

        // 修改原始对象的属性值
        original.setAge(30);
        original.getAddress().setCity("Shanghai");

        System.out.println("修改后原始对象:" + original);
        System.out.println("修改后克隆对象:" + cloned);
    }

    static class Address {
        private String country;
        private String city;

        public Address(String country, String city) {
            this.country = country;
            this.city = city;
        }

        public String getCountry() {
            return country;
        }

        public void setCountry(String country) {
            this.country = country;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        @Override
        public String toString() {
            return "Address{" +
                    "country='" + country + '\'' +
                    ", city='" + city + '\'' +
                    '}';
        }
    }

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

在这个示例中,我们定义了一个ShallowCloneExample类实现Cloneable接口,并重写了clone()方法。同时,还定义了一个Address类作为ShallowCloneExample类的一个属性。

在main()方法中,我们创建了一个ShallowCloneExample对象,然后通过克隆方式复制出另一个对象。接着,我们修改原始对象的属性值,并输出两个对象的内容。由于浅克隆只复制对象本身,而不复制对象持有的引用对象,因此修改地址对象的属性会影响到两个对象。

最终输出结果如下:

原始对象:ShallowCloneExample{name='Tom', age=20, address=Address{country='China', city='Beijing'}}
克隆对象:ShallowCloneExample{name='Tom', age=20, address=Address{country='China', city='Beijing'}}
修改后原始对象:ShallowCloneExample{name='Tom', age=30, address=Address{country='China', city='Shanghai'}}
修改后克隆对象:ShallowCloneExample{name='Tom', age=20, address=Address{country='China', city='Shanghai'}}

可以看出,修改原始对象的属性值后,两个对象的地址对象都发生了变化。这说明浅克隆只是复制

三、深拷贝和浅拷贝区别是什么

Java中的对象复制可以分为深拷贝和浅拷贝两种方式。

浅拷贝:浅拷贝是指复制一个对象时,只复制其基本数据类型的属性值,而不复制其引用类型的属性值。也就是说,在浅拷贝中,原始对象和副本对象中的引用类型属性共享同一个对象实例,因此如果在副本对象中修改引用类型属性,会影响到原始对象。

深拷贝:深拷贝是指复制一个对象时,不仅要复制其基本数据类型的属性值,还要复制其引用类型的属性值。也就是说,在深拷贝中,原始对象和副本对象的引用类型属性分别存储在不同的内存地址中,彼此互不影响。

对于Java中的大部分基本类型(如int、double等),以及String类型,它们都是值传递,即进行赋值或传递参数时,是将变量值直接传递给另外一个变量,而不是传递该变量所指向的内存地址。因此,对于这些类型的变量,无论使用浅拷贝还是深拷贝,均不会存在问题。

但是对于自定义的对象类型,由于其包含了引用类型的属性,因此在使用赋值或传递参数的过程中,实际上传递的是对象的引用地址。因此,在进行浅拷贝时,只是复制了引用地址,因此原始对象和副本对象之间会共享同一个引用类型属性,可能会出现互相影响的情况。而在进行深拷贝时,每个引用类型属性都会重新创建一个新的对象,因此原始对象和副本对象之间的引用类型属性是完全独立的,不会互相影响。

下面是一个使用浅拷贝和深拷贝的示例代码:

import java.util.Arrays;

public class CloneExample implements Cloneable {
    private int[] data;

    public CloneExample(int[] arr) {
        this.data = arr;
    }

    public void setData(int[] arr) {
        data = arr;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        int[] arr = {1, 2, 3};
        CloneExample obj1 = new CloneExample(arr);

        // 浅拷贝
        CloneExample obj2 = (CloneExample) obj1.clone();
        System.out.println("浅拷贝前的数据:" + Arrays.toString(obj1.data));
        obj2.setData(new int[]{4, 5, 6}); // 修改obj2的data属性
        System.out.println("浅拷贝后的数据:" + Arrays.toString(obj1.data)); // 输出obj1的data属性

        // 深拷贝
        int[] arr2 = {7, 8, 9};
        CloneExample obj3 = new CloneExample(arr2);
        System.out.println("深拷贝前的数据:" + Arrays.toString(obj3.data));
        CloneExample obj4 = (CloneExample) obj3.clone();
        obj4.setData(new int[]{10, 11, 12}); // 修改obj4的data属性
        System.out.println("深拷贝后的数据:" + Arrays.toString(obj3.data)); // 输出obj3的data属性
    }
}

在这个示例中,我们定义了一个类CloneExample,包含一个int类型数组data。首先我们创建了一个原始对象obj1,并使用浅拷贝将其复制到obj2中,然后修改了obj2的data属性,并输出了obj1的data属性,可以看到obj1的data属性也被修改了。接着我们使用深拷贝将另一个数组arr2所对应的对象复制到obj3中,

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张燕沨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值