java克隆--浅拷贝和深拷贝

1、克隆

克隆的含义就是:根据一个类复制另一个类,这个新的类内容与源类是相同的,但是内存地址不同。

在java中使用克隆的方式是:实现Cloneable 接口并实现clone()方法即可,一般是super.clone(),因为Cloneable是一个空接口

2、浅拷贝

克隆得到的类,只克隆了基本数据类型的数据,而没有克隆引用数据类型的数据,比如类中引用的对象等。具体如下面示例:

public class MSTest {

    public static void main(String[] args) throws Exception{
        UserInfo userInfo,userInfo2,userInfo3;
        userInfo = new UserInfo();
        userInfo2 = (UserInfo) userInfo.clone();

        //克隆后两个对象内容相等但在内存中的位置不同
        System.out.println(userInfo == userInfo2);      //false
        System.out.println(userInfo.equals(userInfo2));//true

        //克隆后两对象中的引用类型是同一个,因此没有完全克隆
        System.out.println(userInfo.getBody() == userInfo2.getBody());   //true
        System.out.println(userInfo.getBody().equals(userInfo2.getBody())); //true

    }
}

@Data
class UserInfo implements Cloneable{
    private String name;
    private String address;
    private int age;
    private Body body = new Body("111","222");

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserInfo userInfo = (UserInfo) o;
        return age == userInfo.age &&
                Objects.equal(name, userInfo.name) &&
                Objects.equal(address, userInfo.address) &&
                Objects.equal(body, userInfo.body);
    }

}

@Data
class Body{
    private String heigh;
    private String weight;

    Body(String heigh,String weight){
        this.heigh = heigh;
        this.weight = weight;
    }
}

3、深拷贝

深拷贝会创建一个新的对象,并复制原对象的所有内容。对于引用数据类型,深拷贝会递归地复制其所有引用,直到基本类型,然后复制这些基本类型的值。
实现方式:
1、递归调用clone()

@Override
protected Object clone() throws CloneNotSupportedException {
    UserInfo userInfo = (UserInfo) super.clone();
//获取了对象的基础类型,若对象中有引用类型,则它的clone()中也需要去获取这个引用的clone()
    userInfo.body = (Body) userInfo.getBody().clone();
    return userInfo;
}

@Data
class Body implements Cloneable{
    private String heigh;
    private String weight;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    Body(String heigh, String weight){
        this.heigh = heigh;
        this.weight = weight;
    }
}

2、通过序列化获取

@Data
class UserInfo implements Cloneable,Serializable {
    private String name;
    private String address;
    private int age;
    private Body body = new Body("111","222");


    protected Object clone() throws CloneNotSupportedException {
        UserInfo userInfo = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            userInfo = (UserInfo) ois.readObject();
        }catch (Exception e){
            e.printStackTrace();
        }
        return userInfo;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserInfo userInfo = (UserInfo) o;
        return age == userInfo.age &&
                Objects.equal(name, userInfo.name) &&
                Objects.equal(address, userInfo.address) &&
                Objects.equal(body, userInfo.body);
    }
}

4、深拷贝与浅拷贝区别

浅拷贝不拷贝引用类型,只是复制了对象的引用,而不进行创建对象。深拷贝会递归复制其所有引用,直到基本类型,然后复制这些基本类型的值。

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,浅拷贝深拷贝都是用于复制对象的概念。 浅拷贝是指创建一个新对象,然后将原始对象的非静态字段复制到新对象中。如果字段是基本型,则对该字段执行逐位复制;如果字段是引用型,则复制引用而不是引用的对象。 深拷贝是指创建一个新对象,然后递归地复制原始对象及其所有引用的对象。这意味着在深拷贝中,即使字段是引用型,也会创建一个新的对象并复制其内容。 要实现浅拷贝,可以使用`clone()`方法。该方法在`Object`中定义,并且可以由任何继承和覆盖。要使一个支持克隆,需要实现`Cloneable`接口,并且覆盖`clone()`方法。 示例代码如下: ```java class MyClass implements Cloneable { private int value; private MyObject obj; public MyClass(int value, MyObject obj) { this.value = value; this.obj = obj; } public int getValue() { return value; } public MyObject getObj() { return obj; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } class MyObject { private String name; public MyObject(String name) { this.name = name; } public String getName() { return name; } } public class Main { public static void main(String[] args) throws CloneNotSupportedException { MyObject obj = new MyObject("Object 1"); MyClass obj1 = new MyClass(10, obj); MyClass obj2 = (MyClass) obj1.clone(); System.out.println(obj1.getObj().getName()); // Output: Object 1 System.out.println(obj2.getObj().getName()); // Output: Object 1 obj.setName("Object 2"); System.out.println(obj1.getObj().getName()); // Output: Object 2 (原始对象和浅拷贝对象引用同一个对象) System.out.println(obj2.getObj().getName()); // Output: Object 2 } } ``` 需要注意的是,浅拷贝复制了对象的引用,而不是对象本身。因此,如果修改了原始对象中的引用对象,那么浅拷贝对象也会受到影响。 要实现深拷贝,可以使用序列化和反序列化。通过将对象写入字节流,然后从字节流读取对象,可以创建一个全新的对象。这种方法需要确保所有相关的都实现了`Serializable`接口。 示例代码如下: ```java import java.io.*; class MyClass implements Serializable { private int value; private MyObject obj; public MyClass(int value, MyObject obj) { this.value = value; this.obj = obj; } public int getValue() { return value; } public MyObject getObj() { return obj; } } class MyObject implements Serializable { private String name; public MyObject(String name) { this.name = name; } public String getName() { return name; } } public class Main { public static <T> T deepCopy(T object) throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(object); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (T) ois.readObject(); } public static void main(String[] args) throws IOException, ClassNotFoundException { MyObject obj = new MyObject("Object 1"); MyClass obj1 = new MyClass(10, obj); MyClass obj2 = deepCopy(obj1); System.out.println(obj1.getObj().getName()); // Output: Object 1 System.out.println(obj2.getObj().getName()); // Output: Object 1 obj.setName("Object 2"); System.out.println(obj1.getObj().getName()); // Output: Object 1 (原始对象和深拷贝对象引用不同的对象) System.out.println(obj2.getObj().getName()); // Output: Object 1 } } ``` 通过序列化和反序列化可以实现深拷贝,因为它会创建一个全新的对象,而不是引用原始对象的对象。这样,即使修改了原始对象中的引用对象,深拷贝对象也不会受到影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值