学习effective java-11对所有对象共同的方法之覆写clone方法时请慎重考虑

该知识点是自己从书籍中学习的笔记。

    Cloneable接口最开始设计目的是打算作为最小的clone接口,如果对象实现了它的话,那么就说明该对象具有clone的权限。但是实际上该接口并没有达到此要求,因为该接口里面什么也没有。但是Object中有clone方法,并且是protected。

     不能够因为一个对象实现了Cloneable接口,就可以通过反射的方式来调用clone方法。即使反射调用也可能会失败,因为这里并不能够保证每个对象有具有可访问的clone方法。如果一个类实现了Cloneable,则Object的clone方法就返回该对象的逐域拷贝。

     在子类中调用super.clone()方法获取到的是该子类的实例。如果在clone方法中通过构造方法来建立一个对象的话,那么就得不到正确的实例类。因此,如果要重写一个非final的clone方法时,请在clone方法中调用super.clone来获取本类的实例。

      一个比较好的clone方法可以调用构造方法来创建对象,构造之后再复制内部数据。如果这个类是final的,clone甚至可以返回一个有构造方法创建的对象。

      从jdk1.5开始,当子类重写父类的方法时,子类的重写方法的返回类型可以是父类返回类型的子类类型。这样做的目的是可以给客户端提供更多的类的信息以及减少了类型转换工作。

      实际上,clone方法是另一个构造方法,你必须确保它不会伤害到原始的对象,并且正确地建立起被克隆对象中的约束关系。基本规定:clone结构与指向可变对象的final域的正常用法是不兼容的,除非原始对象和克隆对象之间可以安全地共享此可变对象。为了能够使一个类能够被克隆,请尽量将某个域的final修饰符去掉。递归调用clone往往还不够。

      克隆复杂对象的最后一个办法是:先调用super.clone,然后把结果对象中的所有域都设置到它们的空白状态(初始状态),然后调用高层的方法来重新产生对象的状态。和构造方法一样,clone方法不应该在构造过程中调用新对象中任何非final方法,因为会破坏原始对象和新对象之间的状态。

Object的clone方法是抛出了CloneNotSupportedException,如果一个类是重写了这个方法的话,那么可以不声明此异常,因为Public clone方法用起来比有异常更舒服。如果一个类是继承父类重写clone方法的话,那么就应该模仿Object的clone的样式,将clone声明成protected,并且抛出异常。

       总之,如果所有实现了Cloneable接口的类,并且都用public重写了clone方法,返回类型是本类型的话,那么就需要首先调用super.clone,然后将需要的值一个一个的复制。克隆分为:深度克隆、浅克隆。如果一个克隆的对象含有可变对象的引用,就需要深度克隆。如果一个克隆对象仅仅包含原始数据类型和不可变对象,则不需要克隆。当然也有些例外,如代表序列号、唯一id、或者代表对象创建时间的域,不管是原始数据还是不可变对象,都需要复制。

       如果你实现了Coneable接口的话,那么除了实现clone方法外就没有其他方法了。否则的话,你就必须提供其他途径来建立对象copy或者就不提供copy方法。

       对于克隆来说,并不一定要克隆。比如说,对于不可变对象,则可以不必进行克隆,因为它和原始对象没有任何区别。

       另外一个实现对象拷贝的方法是提供一个拷贝构造方法,该方法仅仅包含一个参数(就是该类的类型参数)。如:

          Public Copy(Copy copy){}

        另外一个就是拷贝构造方法的微型,提供一个工厂方法,如:

           Public static Copy getNewInstance(Copy copy){}

        使用拷贝构造方法或者工厂方法来获取Clone对象的优势:不依赖于某一种很有风险、语言之外的对象创建机制;不要遵守尚未良好文档化的规范;不会与final域的正常使用发生冲突;不会要求客户捕获不必要的被检查异常;为客户提供了一个静态类型化的对象。另外它们都可以带一个参数,该参数类型可以是接口类型的。例如通用集合实现都提供了一个拷贝构造函数,它们的参数类型都是Collection或Map。基于接口的拷贝构造方法运行客户来选择拷贝动作的具体实现,而不强迫客户接受原始的实现。

         由于Coneable接口有很多的缺陷,建议不要使用它。

发布了42 篇原创文章 · 获赞 0 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章