(8) javaSE -- Clonable 深浅拷贝

1. Cloneable

java.lang.Cloneable: 克隆接口

程序中的克隆: 赋值一个新的对象,新的对象的属性值是从就对象中拷贝过来的

public interface Cloneable {
    	
}

空接口:标记当前类可以被克隆,也称为 标记接口
克隆标记本身没有任何抽象方法,
当一个类实现了Cloneable接口,就表示该类具备了克隆的能力(JVM)
在堆上开辟空间和对象创建都是有JVM操作的,
JVM会识别所有克隆标识的类,	赋予克隆的能力

1.1 对象的“拷贝” ,

需要先 实现 Cloneable 接口, 否则会抛出异常 CloceNotSupportedException
然后需要重写 Object 类中的 Clone 方法, 调用这个方法可创建一个对象 “拷贝”

1.2 覆写Object 类提供的clone方法

在这里插入图片描述

native: 本地方法,由C++实现(JVM由C++实现) ,
           此处只是方法申明, 也没有方法体 ,并不是抽象方法。
 // 1、需要实现 Cloneable
public class CloneableTest  implements Cloneable {
    public String name;

    @Override
    // 2、clone 方法需要 抛出异常 CloneNotSupportedException
    protected CloneableTest clone() throws CloneNotSupportedException {
        return (CloneableTest) super.clone();
    }
    
    public static void main(String[] args) throws  CloneNotSupportedException{
        CloneableTest c = new CloneableTest();
        c.name = "I am test";
        // c1  通过引用 (c 引用对象的拷贝) 新拷贝对象
        // 创建一个新的引用对象,将属性值进行拷贝
        CloneableTest c1 = c.clone();
        System.out.println(c == c1);
        System.out.println(c1.name);
        System.out.println(c);
        System.out.println(c1);
    }
}


#console
    false
    I am test
    CloneableTest@4554617c
    CloneableTest@74a14482

此时我们会发现

首先会对 c 所引用的对象(CloneableTest@4554617c) 进行拷贝,
将 拷贝对象 (CloneableTest@74a14482)赋值给新的引用 c1

在这里插入图片描述

   对象通过clone方法我们在堆上克隆了一个副本,并将这个副本对象赋给了一个新的引用,
并且当我们修改c1这个引用所指向对象中所包含的简单类型name的值时,c2这个引用所指向对象中所包
含的简单类型String的值并没有发生改变,那么这种情况我们便称之为**深拷贝**

深拷贝拷贝源对象 与 拷贝对象 完全脱离关系,互不干扰

即当拷贝结束后,通过一个新的引用修改所拷贝的新的对象的其中的某个类型的值时,
并不影响原来引用所对应的相同对象中的相同类型的值,那么此时便为深拷贝

1.3 Clonable接口结合浅拷贝


public class A {
    int num;
}

class B implements Cloneable{
    public A a = new A();

    protected  B clone() throws CloneNotSupportedException {
        return (B) super.clone();
    }

}


public class Main {
    public static void main(String[] args) throws  CloneNotSupportedException{
        B b1 = new B();
        b1.a.num = 10;
        B b2 = b1.clone();
        System.out.println("b1.a.num = "+ b1.a.num  + ", b2.a.num = "+ b2.a.num );
        System.out.println(b1 == b2);
        System.out.println(b1);
        System.out.println(b2);
        b1.a.num = 20; // 修改 num值,克隆对象 属性a.num也随之改变
        System.out.println("b1.a.num = "+ b1.a.num  + ", b2.a.num = "+ b2.a.num );
    }
}


#console
    b1.a.num = 10, b2.a.num = 10
    false
    B@1540e19d
    B@677327b6
    b1.a.num = 20, b2.a.num = 20

在这里插入图片描述

C2 克隆对象,只是对 C1 克隆源对象做了简单的浅拷贝,  并未对 C1成员对象进行拷贝,
 C1.a 与 C2.a 引用了相同的对象,当其中一个成员修改后,另一个成员也随之修改,
即 也应该 将  C1.a 所引用的对象实例也需要进行拷贝。这种现象,称之为浅拷贝。

浅拷贝: 拷贝源对象 与 拷贝对象 没有脱离关系,互相干扰

即其当一个新的引用去修改其克隆过来的对象中的某个类型(此段代码为引用类型)的值后,
原引用调用这个类型时便会发现这个值为新修改后的值了,并不是原来的值。

如何实现深拷贝

(1) 递归实现Cloneable , 重写 clone
(2) 通过序列化实现拷贝     

public class A implements  Cloneable{
    int num;
    protected A clone() throws CloneNotSupportedException {
        return (A) super.clone();
    }
}

class B implements Cloneable{
    public A a = new A();

    protected  B clone() throws CloneNotSupportedException {
        //克隆b所指向的对象
        B b = (B) super.clone();
        
        //克隆B 类中的另一个引用类型m所指向的对象
        // this.a.clone() = A 
        b.a = this.a.clone();
        return b;
    }

}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值