【问题标题】:If you don't clone in Java then what do you do and what do you call it?如果你不在 Java 中克隆,那么你会做什么,你怎么称呼它?
【发布时间】:2010-11-08 09:15:46
【问题描述】:

是否有人对 Java 中的复制构造函数/工厂方法等有任何建议或已建立的最佳实践和命名约定?特别是,假设我有一个类Thing,并且我想要一个方法返回一个新的Thing,其值与传入的Thing 相同(或者如果它是实例方法,则作为实例)。你会把它作为构造函数还是静态工厂方法或实例方法?你会怎么称呼它?

根据标题,我想避免clone()Cloneable

【问题讨论】:

  • 为什么要避免 clone() 和 Cloneable?
  • @Thomas Owens,见这里:artima.com/intv/bloch13.html
  • 对于将复制构造函数作为解决方案的答案:复制构造函数不能正确处理所有情况。例如,当您不知道具体类时(但您仍然可以在 clone/copy/whateveryoucallit 方法中使用复制构造函数)。

标签: java oop


【解决方案1】:

Effective Java 推荐以下任一方法:

  1. 复制构造函数(如其他人所述):

    公共物品(物品物品)

  2. 复制工厂方法:

    public static Item newInstance(Item item)

(另外,不可变对象不能复制)

主要区别在于#1 您选择结果的实际类,而#2 实现者可以返回一个子类。类的语义可能会指导您选择哪个是最好的。

【讨论】:

    【解决方案2】:

    我会称它为复制方法或复制构造函数(视情况而定)。如果是静态方法,那我就称它为工厂。

    就做什么而言,最灵活和最长寿的选择是复制构造函数。这使子类能够像父类一样复制自己。

    【讨论】:

      【解决方案3】:

      我会做一个构造函数

      ...
      public Thing(Thing copyFrom)
      {
          attr1 = copyFrom.attr1;
          attr2 = copyFrom.attr2;
          //etc...
      }
      

      然后当你想克隆它时

      Thing copy = new Thing(copy from me);
      

      【讨论】:

        【解决方案4】:

        如果需要,您可以覆盖clone()-方法。另一种使用的做法是构造函数,它采用这种类型的对象,即new ArrayList(anotherList)

        【讨论】:

          【解决方案5】:

          你有几个选项,实现Cloneable,添加一个复制构造函数,但我更喜欢的方法是使用一个方法(静态或实例),它的名称描述了复制操作正在做什么 - 是它是深拷贝还是浅拷贝等。

          【讨论】:

            【解决方案6】:

            使用immutable data structures。你觉得你需要clone() 的唯一原因是你正在改变你的对象。别那样做。想想你可以怎么做:

            • 让您的课程成为最终课程。
            • 将您的类中的字段设为最终和私有。

            例如,这里有一个用于不可变 3D 矢量对象的“setter”:

            public Vector3D setX(double x) {
              return new Vector3D(x, this.y, this.z);
            }
            

            所以我想我要说的是......我使用复制构造函数而不是突变,我只是根据我想要修改的属性来命名它们。

            【讨论】:

              【解决方案7】:

              另一种选择是在 source 对象中实现复制方法,例如:

              interface Has3DCoords {
                  void setLocation(double x, double y, double z);
              
                  void copyCoordsTo(Has3DCoords dest);
              }
              

              然后您将使用如下代码实现复制:

              class Thing implements Has3DCoords {
                  private Point3D loc;
                  // ...
              
                  void setLocation(double x, double y, double z) {
                      loc.setLocation(x, y, z);
                      // or: loc = new Point3D(x, y, z);
                  }
              
                  void copyCoordsTo(Has3DCoords dest) {
                      loc.copyCoordsTo(dest);
                      // or: dest.setLocation(loc.getX(), loc.getY(), loc.getZ());
                  }
              
                  OtherThing createOtherThing() {
                      OtherThing result = new OtherThing();
                      this.copyCoordsTo(result);
                      return result;
                  }
              }
              

              这在以下情况下很有用:

              • 克隆整个对象没有意义
              • 有一组相关的属性经常被复制为一个单元
              • 您不想将loc 公开为Thing 的属性
              • 属性的数量很大(或者有很多这样的组),因此需要所有这些属性作为参数的构造函数会很笨拙。

              【讨论】:

                【解决方案8】:

                这不是复制对象的最佳方法,但如果您希望执行 Serializable 对象的深度复制,以下方法有时会很有用。这避免了编写复制构造函数、实现 Cloneable 或编写工厂类。

                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(bos);
                
                //Serializes the input object
                oos.writeObject(input);
                
                ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
                ObjectInputStream ois = new ObjectInputStream(bais);
                
                //Copy of the input object
                Object output = ois.readObject();
                

                不要忘记处理异常并很好地关闭流。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2014-01-16
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-04-15
                  • 1970-01-01
                  相关资源
                  最近更新 更多