Clonable接口与深拷贝浅拷贝

定义:Clonable接口叫做克隆接口,接口中设有Object.clone()方法,可以对其进行重写达到保留字段副本克隆的目的。

底层源码注释:

该接口专门用于克隆,所以该接口继承java.lang 只需要重写其中的clone()方法。 

翻译:

类实现了可克隆接口,以向Object.clone()方法表明,该方法为该类的实例创建字段对字段副本是合法的。

在未实现Cloneable接口的实例上调用Object的clone方法会导致引发异常CloneNotSupportedException。

按照惯例,实现此接口的类应使用公共方法重写Object.clone(受保护)。有关重写此方法的详细信息,请参见Object.clone()。

请注意,此接口不包含clone方法。因此,不可能仅仅因为对象实现了这个接口而克隆对象。即使以反射方式调用clone方法,也不能保证它会成功

适用范围:

1、自己重写的话可用于Page分页封装类的参数克隆。

2、Java自带的包例如lang、util、array等都有自带对数据的克隆方法的重写。

作用:

克隆的数据应该是暂时放在缓存中,这个是副本思想,总的目的来说:1、保持数据的读写方便搞笑2、防止数据错误,读写不一致,也就是事务中的脏读或者幻读概念,以上是我个人解读,不一定正确hhhhh,

使用示例:

Page工具类clone()的重写:

@Override
        public Page clone() {

            try{
                return (Page)super.clone();
            }catch(CloneNotSupportedException e) {
                final Page page = new Page();
                page.now = now;
                page.size = size;
                page.end = end;
                page.inputPage = inputPage;
                page.count = count;
                return page;
            }
        }

Java自带的ObjectUtil包的clone重写:

public static <T> T clone(final T obj) {
        if (obj instanceof Cloneable) {
            final Object result;
            if (obj.getClass().isArray()) {
                final Class<?> componentType = obj.getClass().getComponentType();
                if (componentType.isPrimitive()) {
                    int length = Array.getLength(obj);
                    result = Array.newInstance(componentType, length);
                    while (length-- > 0) {
                        Array.set(result, length, Array.get(obj, length));
                    }
                } else {
                    result = ((Object[]) obj).clone();
                }
            } else {
                try {
                    final Method clone = obj.getClass().getMethod("clone");
                    result = clone.invoke(obj);
                } catch (final NoSuchMethodException e) {
                    throw new CloneFailedException("Cloneable type "
                        + obj.getClass().getName()
                        + " has no clone method", e);
                } catch (final IllegalAccessException e) {
                    throw new CloneFailedException("Cannot clone Cloneable type "
                        + obj.getClass().getName(), e);
                } catch (final InvocationTargetException e) {
                    throw new CloneFailedException("Exception cloning Cloneable type "
                        + obj.getClass().getName(), e.getCause());
                }
            }
            @SuppressWarnings("unchecked") // OK because input is of type T
            final T checked = (T) result;
            return checked;
        }

        return null;
    }

简单拷贝类Person示例

public class CloneDemo {

    public static void main(String[] args) {
        Person p1 = new Person();
        p1.setName("哈哈哈哈哈");
        Person p2 = p1.clone();
        System.out.println("p1.name = " + p1.getName());
        System.out.println("p2.name = " + p2.getName());
        System.out.println("p1 = p2 ? " + (p1 == p2));
    }
}

class Person implements Cloneable {//谁被克隆,谁要继承Clonable,不然会报错,上面有解释过
    private String name;

    public String getName() {
        return name;
    }

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

    // 实现克隆Person对象,这是经常的实现方法,类似与模板
    @Override
    protected Person clone() {
        Person p = null;
        try {
            p = (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

实现思路:

把需要备份的数据处理过后,例如类型转化过后,判断格式,判断非空等等处理之后调用clone(),进行备份。

此时,改变克隆对象的值不会影响到原对象的值。

如果当需要克隆的对象具有引用类型的时候呢?(引用类型是指在一个类中,引用其他类,作为对象属性。private Person p1)

深拷贝与浅拷贝

引入概念前言

当类中有引用时,将引用类拷贝一份后,发现修改拷贝对象的值还是会影响原对象的值,这是为什么呢?

从拷贝原理上来看,因为拷贝原对象的引用类属性,是拷贝的其属性值(哈希地址)在堆中指向相同的空间,当修改属性值的时候,指向这个空间的栈中的对象被调用的时候,获取到的是修改后的值。

 

这种修改其中一个值,会影响到另一个的拷贝叫做浅拷贝

深拷贝:修改其中一个值,不会影响到另一个的拷贝。

深拷贝实现思路:如果要引用类型的拷贝值不指向同一个空间地址的话,那么,将引用类型也拷贝一份,再去修改值,就可以啦。

使用以上例子来说

class Person implements Cloneable {
    private String name;
    private Student grade;

    public Wallet getGrade() {
        return grade;
    }

    public void setGrade(Student Grade) {
        this.grade = grade;
    }

    public String getName() {
        return name;
    }

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

    @Override
    protected Person clone() {
        Person p = null;
        try {
            p = (Person) super.clone();
            grade = this.grade.clone();//此处是将引用类型的属性值进行克隆,这样不会指向原属性值同一个地址,达到深拷贝
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值