clone方法使用需知

2020-03-16  本文已影响0人  睦月MTK

statement:本篇内容只是建立在我目前经验的基础之上,必然有不完善甚至是不正确的地方,请谨慎阅读,如果能指出错误与不足之处,更是不甚感激


一、使用条件

二、什么样的类不需要重新覆盖clone方法

三、如何实现一个可靠的clone方法

实现一个可靠的clone方法,大体需要遵循下列步骤:

  1. 调用super.clone获取克隆出来的对象
  2. 检查是否有引用类型的字段
    • 如果有,检查该引用类型的字段指向的对象的状态是否是有被改变可能的
      • 如果是,检查该字段是否是final修饰的
        • 如果是,应当考虑能否去掉final修饰,否则将无法进行深克隆
        • 如果不是,应当进行深克隆
      • 如果不是,直接返回super.clone克隆出来的对象
    • 如果没有,直接返回super.clone克隆出来的对象
  3. 判断该类是否是被设计用于继承的
    • 如果是,应当保持clone方法的访问权限为protected,返回类型为Object,同时抛出CloneNotSupportedException异常,并且不应当实现Cloneable接口,应当将是否具有克隆能力的选择权交由子类来决定
    • 如果不是,应当更改clone方法的访问权限为public,返回类型为当前类型,且不建议抛出CloneNotSupportedException异常,应当使用try-catch内部消化该异常,并抛出一个非受检异常。

例子:

@Override
public Student clone(){
    try {
        return (Student) super.clone();
    } catch (CloneNotSupportedException e) {
        throw new AssertionError();
    }
}

注意:


四、深克隆

Q--什么是深克隆?为什么要进行深克隆?
A--因为Objec提供的clone方法只能够做到将字段的值复制到新对象中去,这个特点对于引用类型的字段来说就很糟糕了,这样会使得原体与克隆体和同一个对象关联,修改那个被关联对象的状态,原体和克隆体的状态会同时发生变化,这是不可容许的。所以就要有深克隆,深克隆负责在将一个完全独立于原对象,且又和原对象状态相同的对象交付给使用者。
Q--如何进行深克隆?
A--原理其实很简单,就是对引用类型的字段重新进行修改,修改为调用引用指向的对象的clone方法创建出来的对象。
例子:

public class Test implements Cloneable{
    private int[] arrInt = {1,2,3};

    @Override
    public Test clone(){
        try {
            Test studentClone = (Test) super.clone();
            studentClone.arrInt = arrInt.clone();
            return studentClone;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
    
    public static void main(String[] args) {
        Test testOrigin = new Test();
        Test testClone = testOrigin.clone();
        System.out.println("testOrigin.arrInt == testClone.arrInt ====> "+ (testOrigin.arrInt.equals(testClone.arrInt)));
        System.out.println("testOrigin.arrInt equal testClone.arrInt ====> "+ (Arrays.equals(testOrigin.arrInt, testClone.arrInt)));
    }
}

/* result:
testOrigin.arrInt == testClone.arrInt ====> false
testOrigin.arrInt equal testClone.arrInt ====> true
*/

注意:


五、总结

一句话,没有绝对的必要不要去启用clone方法。作为替代,你可以尝试下“拷贝构造器”,像是这样

public Test newInstance(Test test) {
    Test cloneTest = new Test();
    cloneTest.arrInt = Arrays.copyOf(arrInt, arrInt.length);
    return cloneTest;
}

当然实际上并不一定要以相同的类型返回,决定权完全在你手里。


参考文档:

上一篇下一篇

猜你喜欢

热点阅读