clone方法的思考

事情起因

某个同学希望某个类可被clone,该类其实继承HashMap,本身有clone,但是该同事不知道,所以写了一个clone方法

@Override
    public Object clone() {
        return SerializationUtils.clone(this);
    }

结果他的代码正常,其它地方在clone的时候,报了另外一个类java.io.NotSerializableException

原因分析

1.该类原先继承HashMap,所以原来clone是调用HashMap的clone(value值为浅拷贝)
2.该类的clone方法被同学覆盖,使用的是SerializationUtils.clone(深拷贝)
3.SerializationUtils.clone方法需要类实现Serializable,并且如果其包含的属性非原生数据类型,其属性类也需要实现Serializable

解决方案

解决方案一

如果项目只需要浅拷贝,获取值,而不改变值里面的内容,则可以使用HashMap的clone方法

解决方案二

如果项目需要做深拷贝,可能改变值里面的内容,那么需要重写clone方法,可以SerializationUtils.clone,但是类及其子类都需要实现Serializable接口

总结思考

浅拷贝&深拷贝

浅拷贝:如果基本数据类型则拷贝一份,非基本类型(包括数组)都只是拷贝引用,所以非基本数据类型原始值修改,则拷贝也会修改
深拷贝:无论是否基本数据类型都会做一份拷贝

HashMap的clone

hashmap的拷贝,看代码

public Object clone() {
    HashMap<K,V> result;
    try {
        result = (HashMap<K,V>)super.clone();
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
    result.reinitialize();
    result.putMapEntries(this, false);
    return result;
}

HashMap的clone方法,map会生成新的对象,但新的HashMap所存储的引用类型还是原来Map的值,hashmap的clone本身map会复制一份,但是其value值是一个浅拷贝。

浅拷贝实现方式

通过实现Cloneable接口

java实现一个类的浅拷贝,则只需要实现Cloneable接口,同时覆盖重新Objec的clone方法即可

public class MyClass implements Cloneable{
    Integer num;
    MySubClass mySubClass;

    public MyClass(Integer num, MySubClass mySubClass) {
        this.num = num;
        this.mySubClass = mySubClass;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }

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

为什么要实现Cloneable接口,这个接口没有任何方法;其实只是打上一个标识,在Object的native clone方法中有一段代码就是判断是否实现该接口。可能是为了表示有些类可以clone,有些类不能clone吧。

通过BeanUtils

使用apache的Common BeanUtils,pom文件引入

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.4</version>
</dependency>

代码如下:

MySubClass mySubClass1 = (MySubClass)BeanUtils.cloneBean(mySubClass);
System.out.println(mySubClass1);

其原理是通过反射创建一个新对象,然后通过copyProperties方法将类的值一个个拷贝,因此是一个浅拷贝

深拷贝实现方式

当然深拷贝有自身实现的方式,比如还是继续重写clone方法,在clone方法中将非基本数据类型new出一个新对象,子对象也是重新clone方法,这样会比较繁琐。这里有些工具类可供选择

Apache Commons Lang序列化方式深拷贝

MyClass myClass = new MyClass();//该类必须实现Serializable接口
SerializationUtils.colne(myClass);

其原理是通序列化和反序列化的方式,重新生成对象。不过需要每个类都实现Serializable接口

Gson或者JackJson序列化方式深拷贝

其原理也差不多,是同步序列化成json对象,再反序列化。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值