返回数组列表的 const 引用

Posted

技术标签:

【中文标题】返回数组列表的 const 引用【英文标题】:Returning const reference of an arraylist 【发布时间】:2011-05-14 19:53:41 【问题描述】:

我真的很佩服java的特性,下一个问题我不想放弃使用它:

我有一个可能被继承的类,它的内部是一个private ArrayList arr; 所以setter 函数没问题,但是getter 函数return arr; 返回对该变量的引用,任何人都可以编辑整个数组我不想要,而且私人没有任何意义!

在 C++ 中,我只需要 return const arr;,它会返回对变量的常量引用。

我非常需要不要克隆或手动复制该变量,因为有太多计算需要(只读变量)为什么在 java 中没有返回 const ????有什么办法可以避免抄袭?

p.s (final ArrayList<Integer> arr;) 不是一个选项,因为数组总是改变大小或元素值。

如果我找不到解决方案,我威胁要回到 C++ 或公开所有内容,你永远不应该得到我的软件 :D


编辑:一个更重要的问题:我是否要求一些不好的东西(软件工程方面)我的意思是如果 JAVA 创建者认为没有 const 引用(返回只读引用),那么我必须要求一些可以以其他方式处理。或者我的程序设计错了我很困惑。

【问题讨论】:

@GMan:我不同意。如果某些东西在 C++ 中是个好主意,那么值得学习在其他语言中等效的好主意(如果有的话)。如果没有,那会教你一些关于这两种语言的知识。如果 Bjarne Stroustrup 在 C 编程时没有考虑 Simula,那么我们就不会有 C++ ;-) 错误是假设如果某件事在 C++ 中是一个好主意,那么它一定是一个好主意其他语言。 @Steve:我不同意。为什么不直接去掉“等价”这个词呢? “其他语言中的好主意是什么” 您无需事先了解任何语言即可学习好主意。它不会让你有一些不同的好主意,只会让你误入歧途。那么,在尝试学习一门新语言的同时梦想一门不同的语言有什么好处呢?我会说发明一门新语言与学习一门新语言是完全不同的任务。 @GMan:白日梦的好处是,如果 ismail 不熟悉 C++ 中的 const 引用,那么他就不会那么容易想到限制他的调用者读取而不是写入他的 ArrayList .诚然,他本可以在问题中少提及 C++,并专注于 const 引用实际完成的核心任务。我认为通过了解多种语言和范式,以及了解哪些可以翻译,哪些不能翻译,可以获得很多。我不认为 Stroustrup 打算发明一门新语言——当 C 没有做他想做的事情时,他必须这样做。 我实际上认为这个问题问得很好。除了威胁要放弃 Java (幽默,但我不会完全排除它作为解决方案),它显然是在询问提问者碰巧遇到的问题的 Java 解决方案是什么知道如何在 C++ 中解决,因此期望在 Java 中很可能有解决方案。它确实有一个,尽管提问者对它不需要一个的可能性持开放态度。对我来说,这正是将编程经验应用于学习一门新语言的正确方法 - 有一个想法,但如果它不成功,不要强迫它。 我确实认为[c++] 标签很奇怪。问题是关于 Java 的,仅仅因为它引用了 C++ 的一个特性并不能真正使它成为 C++ 标记,不是吗?除此之外,我认为@Steve 是对的,提及 C++ 很好。 【参考方案1】:

java.util.Collections.unmodifiableList 包装返回值。它不会复制数据,而是包装原始列表,并将只读操作委托给底层列表。在运行时会通过UnsupportedOperationException 拒绝修改列表的操作。

你的

return arrayList;

变成

return Collections.unmodifiableList(arrayList);

不幸的是,编译器不会强制执行只读约束。但是,它们将在运行时强制执行。

您还可以使用:unmodifiableSet、unmodifiableMap、unmodifiableCollection、unmodifiableSortedSet 和 unmodifiableSortedMap。如果这些还不够,您仍然可以从这种通用设计方法中汲取灵感,并创建自己的自定义只读包装类。

【讨论】:

“创建您自己的自定义只读包装类” - 我开始重新实现一次不可修改的集合(主要作为代码大小优化)。原来我使用的非 javac 编译器对每个源文件的内部类总数有限制。以前没有人打过它。并不是说你做不到,但与在 C++ 中实现一个 const 正确的类相比,Java 中的只读包装器需要更多的努力来证明这一点。 “并不是说你做不到,但与在 C++ 中实现一个 const-correct 类相比,Java 中的只读包装器需要更多的努力来证明这一点。” i> Steve,我倾向于同意。在我最新的项目中,使用“文档合同只读,违反合同造成问题是类消费者的错,而不是类的错”被认为是可以接受的。但是,这绝对不是所有人在所有情况下都可以接受的。在某些关键情况下,我们通过复制而不是引用传递/返回。我有时会想念const,但没有它我们相处得很好。【参考方案2】:

:) 你有几个选择:

不要暴露getter,只提供允许调用的方法,例如

public void addToList(Object arg) this.arr.add(arg);

返回不可变对象:

public List getArr() return Collections.unmodifiableList(this.arr);

【讨论】:

【参考方案3】:

您也可以使用Google Guava 的不可变collections。在这种情况下,您将在您的字段中存储一个ImmutableList。

当然,如果你的类需要在内部修改这个列表,那么使用 ImmutableList 可能是个坏主意,因为你需要创建一个新的 ImmutableList 实例并将其重新分配给每次字段...

但是当你知道 List 在对象构造后不会改变时,这是完美的。

不可变示例(对象构造后列表不会改变)

@Immutable
public final class Foo 

    @Nonnull
    private final ImmutableList<String> list;

    public Foo(@Nonnull List<String> list) 
        // you could also compute the appropriate list here
        // before assigning it to the field
        this.list = ImmutableList.copyOf(list);
    


    public ImmutableList<String> getList() 
        return list;
    

可变示例(列表只能使用 setter 修改)

public class Foo 

    @Nonnull
    private ImmutableList<String> list = ImmutableList.of();

    public ImmutableList<String> getList() 
        return list;
    

    public void setList(@Nonnull List<String> list) 
        this.list = ImmutableList.copyOf(list);
    

备注

我知道通常建议让方法返回尽可能通用的类型(在本例中为 List),但我更喜欢将我的 getter 的返回类型声明为 ImmutableList,因为它充当文档(无需在 Javadoc 中记录返回列表的不变性)并作为 API 契约。这就像说“我保证此列表是不可变的,您不必担心或防御性地复制它”。而且非常简洁。 ImmutableList.copyOf() 很棒,因为它会自动拒绝空列表(通过抛出 NullPointerException)。它还拒绝空元素。如果源列表已经是 ImmutableList,它不会复制源列表,从而避免了无用的对象实例化。 在第二个示例中,我使用 ImmutableList.of() 将字段初始化为空的 ImmutableList,因为返回空集合而不是空值 (Null Object pattern) 是一种很好的做法。您可能认为这会创建不必要的对象实例化,但 ImmutableList.of() 实际上返回一个单例。

【讨论】:

【参考方案4】:

unmodifiableList 绝对是答案。

【讨论】:

以上是关于返回数组列表的 const 引用的主要内容,如果未能解决你的问题,请参考以下文章

4 C++基础4 类 const函数 转全局函数 返回*this 数组类。友元 函数 类 操作符重载

c语言中返回结构体数组

《C++ Primer》学习 之 返回数组的引用(返回数组的指针,方法与之相同)

动态数组

通过引用返回指针数组

C ++:从函数、返回类型或引用中使用和返回字符数组?