【java】关于浅克隆和深克隆的理解

1.对象克隆

对象克隆就是把A的对象的属性值完全拷贝给B对象,也叫对象拷贝,对象复制。那我们要克隆有什么用那?举个很简单的例子,比如,一直很火的游戏LOL有很多的服务器,但是正因为服务器多的原因,你可能和你的朋友不在一个区服内,而这时候就需要“转区”,那么此时,就要用到对象克隆

2.演示

首先创建一个User类的Javabean

import java.util.Arrays;
public class User {
    private  int id;//账户ID
    private String password;//密码
    private String usename;//角色ID
    private int[] data;

    public User() {
    }

    public User(int id, String password, String usename, int[] data) {
        this.id = id;
        this.password = password;
        this.usename = usename;
        this.data = data;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsename() {
        return usename;
    }

    public void setUsename(String usename) {
        this.usename = usename;
    }

    public int[] getData() {
        return data;
    }

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


    public void show(){
        System.out.println("账户ID"+id+"密码"+password+"角色ID"+usename+"通关等级"+ Arrays.toString(data));//此处注意数组要进行字符串转换,不然打印出来的是地址值
    }//打印出地址值原因是默认调用Object类总的toString方法打印该对象的地址值
}

TestClone测试克隆方法

public class TestClone {
    public static void main(String[] args) {
        int data[]={1,2,3,4,5,6,7};
        //先创建一个对象
        User u1=new User(2208,"123456","yhhhhh",data);
        u1.show();
        //克隆对象
        u1.clone();
    }
}

此时,调用对象的clone方法在idea会报错,通过源码分析,原因在于clone方法前的修饰符是protected,他只能被本包中和其他子类中使用,所以我们必须自己重写才行,所以在User中重写一下clone方法,相当于让java帮我们克隆一个对象,并把克隆对象返回出去。并且实现一个Cloneable的接口

//Cloneable
//Cloneable当中没有抽象方法,表示当前的卸扣是一个标记性接口
//现在Cloneable表示一旦实现,那么当前类的对象可以被克隆
//如果没有实现,当前类不能被克隆
public  class  User implements Cloneable{
  protected Object clone() throws CloneNotSupportedException {
  //调用父类clone方法
 // 相当于让java帮我们克隆一个对象,并把克隆对象返回出去
        return super.clone();
    }
    }

TestClone类中改为``


public class TestClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        int data[]={1,2,3,4,5,6,7};
        //先创建一个对象
        User u1=new User(2208,"123456","yhhhhh",data);
        u1.show();
        //克隆对象
      User u2= (User) u1.clone();//向下强转为User类型
      u2.show();
    }
}

输出结果

账户ID2208密码123456角色IDyhhhhh通关等级[1, 2, 3, 4, 5, 6, 7]
账户ID2208密码123456角色IDyhhhhh通关等级[1, 2, 3, 4, 5, 6, 7]

基本数据类型:储存的是真实的值。引用数据类型:储存的是另一个空间的地址值。
在java克隆方式中,有两种克隆方式:
第一种是浅克隆,浅拷贝
浅克隆中创建的对象,会把原来数据全部拷贝过来,如果是基本数据类型,就把记录的数据值拷贝过来,如果是引用数据类型,就会把记录的地址值拷贝过来。对于数组而言,克隆过来的对象和原来的对象使用的是同一个数值,其中一个发生改变,另外一个对象也会发生改变。
在这里插入图片描述

第二种为深克隆,深拷贝
在深克隆中,基本数据仍然会直接拷贝数据值,但如果是引用数据类型,将不会再拷贝地址值,例如数组,而是会再重新创建一个新的数组,把原来数组的数据拷贝过来,两者不再互相干扰。而字符串再串池中已经存在,还会继续复用地址值。
在这里插入图片描述

区别:

浅克隆:不管对象内部的属性是基本数据类型还是引用数据理性,都完全拷贝过来。
深克隆:基本数据类型拷贝过来,字符串复用,引用数据类型会重新创建新的。

验证Object中的克隆是浅克隆

在TestClone中加入

//验证Object中的克隆是浅克隆
int arr[]=u1.getData();
arr[0]=100;

此时再次运行会发现,结果变为

账户ID2208密码123456角色IDyhhhhh通关等级[100, 2, 3, 4, 5, 6, 7]
账户ID2208密码123456角色IDyhhhhh通关等级[100, 2, 3, 4, 5, 6, 7]

第二个克隆的数组跟着改变,所以Object中的克隆是浅克隆。
那么我们该如何进行深克隆那?这时候就要我们自己去写一个深克隆方法
在User类中的clone方法中

 public Object clone() throws CloneNotSupportedException {

        //先把被克隆对象中的数组获取出来
        int[] data=this.data;
        //创建新的数组
        int[] newData=new int[data.length];
        //拷贝数组中的数据
        for (int i=0;i<data.length;i++){
            newData[i]=data[i];
        }
        //调用父类中的方法克隆对象
        User u=(User) super.clone();
        //调用父类中的方法是浅克隆,替换克隆出来对象中的数组地址值
        u.data=newData;
        return u;
    }

此时再次运行TestClone结果为

账户ID2208密码123456角色IDyhhhhh通关等级[100, 2, 3, 4, 5, 6, 7]
账户ID2208密码123456角色IDyhhhhh通关等级[1, 2, 3, 4, 5, 6, 7]

克隆的数组将不会随这被克隆数组改变而改变。其实,我们并不需要自己去写深克隆的方法,我们还可以引入第三方工具来进行深克隆。
将这个工具部署到所用项目中,然后点击OK就能够在项目中使用在这里插入图片描述
再将User类中刚刚写的深克隆删掉,测试gson是否为深克隆
在TestClone中

import com.google.gson.Gson;

public class TestClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        int[] data ={1,2,3,4,5,6,7};
        //先创建一个对象
        User u1=new User(2208,"123456","yhhhhh",data);
        //克隆对象
      //1.将第三方写的代码导入到项目中
      //2.编写代码
      Gson gson=new Gson();
      //把对象变成一个字符串
        String s=gson.toJson(u1);
        //再把字符串变回对象
      User us=  gson.fromJson(s,User.class);
        int[] arr =u1.getData();
        arr[0]=100;
        u1.show();
        us.show();
    }
}

最终结果为

账户ID2208密码123456角色IDyhhhhh通关等级[100, 2, 3, 4, 5, 6, 7]
账户ID2208密码123456角色IDyhhhhh通关等级[1, 2, 3, 4, 5, 6, 7]

可以发现克隆的对象数组并没有改变,所以以后我们进行深克隆时候,可以直接使用第三方工具gson来帮我们完成

  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值