【问题标题】:Best Practice for Returning Object References返回对象引用的最佳实践
【发布时间】:2010-07-11 21:15:40
【问题描述】:

考虑这段代码sn-p:

class MyClass{
    private List myList;
    //...
    public List getList(){
        return myList;
    }
}

由于Java通过值传递对象引用,我的理解是任何调用getList()的对象都将获得对myList的引用,允许它修改myList,尽管它是private。对吗?

而且,如果它是正确的,我应该使用

return new LinkedList(myList);

创建一个副本并传回对副本的引用而不是原始引用,以防止未经授权访问myList引用的列表?

【问题讨论】:

  • 从技术上讲,没有外部客户端能够更改您班级中字段 myList 的值。它始终是 List 的句柄/引用,引用 MyClass 中的某些代码设置的列表。外部客户端将能够修改该列表的内容
  • 是的,这就是我的意思,但我的解释有点草率。我会编辑它
  • +1 Miro A 以获得正确的说明。是的,您通过创建列表副本的解决方案是正确的(对于您想要实现的目标)。

标签: java pass-by-reference


【解决方案1】:

我这样做。更好的是,有时我会使用 Collections API 返回一个不可修改的副本。

如果您不这样做,您的参考资料就不是私人的。任何有参考的人都可以改变你的私人状态。任何可变引用(例如,日期)也是如此。

【讨论】:

  • 如果您提供原始集合的不可修改视图,请注意原始列表中的任何更改都将反映在视图中。使用不可变的集合,生活会简单得多……
【解决方案2】:

这取决于你想要什么。

您想公开列表并制作它以便人们可以编辑它吗?

或者你想让人们看到它,而不是修改它?

在这种情况下,没有对错之分。这仅取决于您的设计需求。

【讨论】:

  • 因此,如果您的设计要求属性具有私有可见性,您应该返回对象的副本而不是简单的引用,以确保它保持封装状态
  • @chris 如果您的设计要求人们不能修改您的列表,那么请传递一份副本。否则传递原始参考。
  • 是的,对不起,这是一个修辞评论,我理解你的回答;)
【解决方案3】:

在某些情况下,您可能希望将“原始”列表返回给调用者。但总的来说,我认为这是一种不好的做法,因为它破坏了封装,因此反对 OO。 如果您必须返回“原始”列表而不是副本,那么 MyClass 的用户应该清楚地知道它。

【讨论】:

    【解决方案4】:

    是的,它有一个名字..“防御性副本”。也建议在接收端复制。正如Tom has noted,如果集合是不可变的,程序的行为更容易预测。因此,除非您有充分的理由,否则您应该使用不可变集合。

    Google Guava 成为Java 标准库的一部分时(我完全认为应该),这可能会成为首选的成语:

    return ImmutableList.copyOf(someList);
    

    void (List someList){
        someList = ImmutableList.copyOf(someList);
    

    这对性能有额外的好处,因为copyOf() 方法检查集合是否已经是不可变集合的实例(instanceof ImmutableList),如果是,则跳过复制。

    【讨论】:

      【解决方案5】:

      我认为将字段设为私有并提供访问器的模式只是为了数据封装。如果您希望某些东西真正私有,请不要给它访问器方法!然后,您可以编写其他方法来返回您的私有数据或其副本的不可变版本。

      【讨论】:

        猜你喜欢
        • 2014-06-16
        • 1970-01-01
        • 1970-01-01
        • 2021-07-18
        • 2016-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-25
        相关资源
        最近更新 更多