返回数组列表的 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 数组类。友元 函数 类 操作符重载