美文网首页
Effective Java - clone

Effective Java - clone

作者: DZQANN | 来源:发表于2022-05-15 22:50 被阅读0次

    第12条 始终要覆盖toString

    1. 覆盖toString可以方便系统调试
    2. toString方法不一定要显示所有信息,应该是显示所有值得关注的信息
    3. 重写toString方法的弊端就是,如果其它人依赖了toString的返回格式,当返回格式变化的时候,就会导致之前的程序出现异常。不管是否指定了toString的格式,都要给toString中包含的信息一个可以访问的API

    个人感觉重写toString的意义不大,真正需要看log的时候,都会直接使用序列化工具或者打印一些核心的字段值,不会选择去重写toString方法来记录log

    第13条 谨慎的覆盖clone

    1. 一个类如果没有实现Cloneable接口,直接重写了clone方法,并且在clone方法里调用了super.clone(),会抛出CloneNotSupportedException。实现Cloneable接口是为了提供一个功能适当的公有clone方法

    2. 只要一个类实现了Cloneable,Object的clone方法就会返回对象的逐个字段的拷贝。

    3. 来自Object规范中的clone方法的通用约定:

      • x.clone() != x
      • x.clone().getClass() == x.getClass()
      • x.clone().equals(x)

      这3点并不是绝对的要求

    4. clone方法的返回值应该是当前类(而不是Object)

    5. immutable的类不应该提供clone方法.

    6. 如果一个类的clone返回的实例不是通过super.clone获得的,那它子类调用super.clone会报错。如果覆盖了非final类中的clone方法,则应该返回一个通过调用super.clone而得到的对象。

      书中提到了一个例子:

      public class Stack {
          private Object[] elements;
          private int size = 0;
          private static final int DEFAULT_INITIAL_CAPACITY = 16;
      }
      

      对于这样一个类,如果知识实现了Cloneable接口,调用了super.clone(),那么elements就会是老的对象的引用,这样就会导致会面两个对象公用同一个elements的副作用。

      所以在覆盖clone的时候,一定要把elements中的元素都复制一遍,并且新建一个数组

    7. 对于比较复杂的数据结构,会需要递归clone

      public class HashTable impement Cloneable {
          private Enrty[] buckets = ...;
          private static class Entry {
              final Object key;
              Object value;
              Entry next;
          }
          Entry(Object key, Object value, Entry next) {
              this.key = key;
              this.value = value;
              this.next = next;
          }
      
          Entry deepCopy() {
              return new Enrty(key, value, next == null ? null : next.deepCopy());
          }
      }
      
      @Override
      public HashTable clone() {
          try {
              HashTable result = (HashTable) super.clone();
              result.bucket = new Entry[bucket.length];
              for(int i = 0; i < buckets.length; i++) {
                  if (buckets[i] != null)
                      result.buckets[i] = buckets[i].deepCopy();
                  return result;
              } catch (CloneNotSupportedException e) {
                  throw new AssertionError();
              }
          }
      }
      
      
      

      这里可以很明显看到,如果buckets的元素太多,会导致栈溢出,比较好的方法是通过迭代进行clone

      Entry deepcopy() {
        Entry result = new Entry(key, value, next);
        for (Entry p = result; p.mext != null; p = p.next()) {
          p.next = new Entry(p.nexy.key, p.next.value, p.next.next);
        }
        return result;
      }
      
    8. 公有的clone方法应该省略throws,为了继承而设计的类不应该实现Cloneable

    9. 如果需要线程安全的Cloneable方法,需要使用synchronized

    10. 另一个实现对象拷贝的方法(更好的方法)是提供一个拷贝构造器或者拷贝工厂:

      public Yum(Yum yum);
      public static Yum newInstance(Yun yum);
      

    以下是个人观点了:

    clone方法的使用,风险还是很高的。之前看到过有人推荐使用序列化进行clone,尝试过使用,体验下来感觉不错,因为不涉及复杂的继承关系,没碰到问题。真正的使用场景中,clone方法应该更多地会用于vo的复制,而vo又是简单的基本数据类型的组合,用序列化会比较合适一点。

    clone方法在TMS中是有过使用的,具体可以等下次review的时候分享

    相关文章

      网友评论

          本文标题:Effective Java - clone

          本文链接:https://www.haomeiwen.com/subject/hihgurtx.html