【问题标题】:Java - Clone the property inside getter methodJava - 克隆 getter 方法中的属性
【发布时间】:2012-09-24 06:00:59
【问题描述】:

伙计们,

我正在学习此处提到的 Java 最佳编码实践
http://viralpatel.net/blogs/most-useful-java-best-practice-quotes-java-developers/

第二句说,

引用 2:永远不要公开类的实例字段

我同意这是绝对正确的,但我因为在这句话下面几行遵循作者的建议而陷入困境。

他说,


private String[] weekdays = 
    {"Sun", "Mon", "Tue", "Thu", "Fri", "Sat", "Sun"};

public String[] getWeekdays() {
    return weekdays;
}

但是写getter方法并不能完全解决我们的问题。该阵列仍然可以访问。使其不可修改的最佳方法是返回数组的克隆而不是数组本身。因此getter方法将更改为

public String[] getWeekdays() {
    return weekdays.clone();
}

我自己从未在 Java 类的任何 getter 方法中使用过clone()

我想知道(因为它被提到是一种好的做法) - 为什么在 getter 方法中有一个 should use / shouldn't use clone() ?以及在哪些情况下?

它是否有资格成为 Java 的良好编码实践?

谢谢

【问题讨论】:

  • IMO - 对于不可变对象和原始数据类型,不需要克隆。对于其他一切,如果我们真的希望我们的数据安全,我们必须返回克隆副本而不是原始副本。
  • 你可以返回Arrays.asList(weekdays),它是不可变的。
  • @Jivings 不正确。 List 不接受新元素,但 set() 方法有效。
  • @SeanPatrickFloyd:是的,完全正确。你仍然可以使用set,只是不要改变大小。我的错。

标签: java coding-style clone getter-setter


【解决方案1】:

这在Joshua Bloch“Effective Java”一书中进行了讨论。有一个部分称为“在需要时制作防御性副本”(第 2 版中的第 39 节)。

https://www.informit.com/articles/article.aspx?p=31551&seqNum=2

一本关于此类主题的好书。

【讨论】:

    【解决方案2】:
    private String[] weekdays =      
        {"Sun", "Mon", "Tue", "Thu", "Fri", "Sat", "Sun"};  
    
    public String[] getWeekdays() 
    {     
        return weekdays; 
    } 
    

    如果不使用clone方法,这个类的用户可以做很多不道德的事情:

    1. 更改天数,
    2. 更改日期名称,
    3. ...

    但是,返回一个克隆不会影响类和它的数据。因此,班级的其他用户不会受到影响。

    【讨论】:

    • 但我之前在任何网站上都没有看到 clone() 方法推荐。我没有看到大多数程序员(甚至一些 Java 极客)在他们的示例中使用它。我怀疑,这是否是一种好的编码习惯? :O
    • @bomslang 你的要求会有很多。正如 Azodious 所指出的,不克隆(证明数据的任何其他副本)可能会给您的班级带来意想不到的问题,但您需要确定这是否是您想要的行为。您可能看不到它的原因是因为它对大多数人来说更容易打字。如果您查看 Swing API,您会看到很多类似的做法,当返回 Dimension 时,该类通常会创建一个新的 Dimension 对象,使用它的内部引用作为该新类的种子,本质上,克隆它。
    • 是的。我个人在与您的示例几乎相似的情况下使用了它。但不宜盲目使用,如果克隆重物,会导致内存问题。因此,只克隆用户不应修改的数据。
    • @Azodious +1 同意!感谢您的回答。
    • @All : 它是否符合在 Java 中遵循的良好编码规范?
    【解决方案3】:

    如果你想保证整个对象图(包含数组)是不可变的,你 clone() or System.arraycopy() 上的 get()。这通常在公开数组的 API 是 public 并且数组中的值存在约束或当对象被多个线程访问时完成。在这种情况下,不变性很重要。

    假设您有一个 GroceryStore 对象,该对象具有 getItemsSortedByPrice() 方法。您将项目保存在按价格维护订单的数组中,但如果您返回此数组,客户端代码可能会修改它并破坏对象的(内部)不变量。

    如果这是内部代码(即)不是公共 API 的一部分,并且您知道不会修改数组,那么克隆/复制可能没有必要,因为它会损害性能而没有真正的好处。

    一切都取决于上下文。

    数组只是对象,适用于普通对象的所有(不)可变性规则/实践也适用于数组。

    【讨论】:

    • +1 for System.arrayCopy(),虽然我推荐更有用的版本 Arrays.copyOf()(当然在内部使用 System.arrayCopy())
    【解决方案4】:

    我认为您的用例与建议的 Java 代码不匹配。该示例适用于与您不同的用例。

    在我看来,最终数组听起来像 Enums,我认为这更符合您的要求。

    【讨论】:

      猜你喜欢
      • 2018-08-20
      • 2012-09-14
      • 2012-12-18
      • 2011-02-08
      • 1970-01-01
      • 2012-12-22
      • 1970-01-01
      • 2016-08-05
      • 1970-01-01
      相关资源
      最近更新 更多