假设我有以下Set
Set<String> fruits = new HashSet<String>();
fruits.add("Apple")
fruits.add("Grapes")
fruits.add("Orange")如果我想创建一个防御性副本,以便如果修改了原始列表,那么副本就不会反映出来,我可以这样做:
Set<String> unmodifiableFruits = Collections.unmodifiableSet(new HashSet(fruits))所以如果我这么做
fruits.add("Pineapple")
println(unmodifiableFruits)unmodifiableFruits不会吃菠萝。
或者我可以这么做:
Set<String> unmodifiableFruits = Collections.unmodifiableCollection(fruits)结果是一样的,unmodifiableFruits不会吃菠萝。
问题:
fruits作为参数传递给类,那么首选的方法是Collections.unmodifiableCollection()吗?原因是,我已经read了,在构造函数中声明new是一个错误的实践,如果我要使用Collections.unmodifiableSet(),我需要声明一个new HashSet<String>(fruits)。
Collections.unmodifiableSet(fruits)并让它返回一个不可修改的集合。
相反,我必须这样做:
Collections.unmodifiableSet(new HashSet<String>(fruits))是因为Set是一个接口,它不知道返回哪个实现?
发布于 2018-08-29 02:34:00
Groovy增强了集合方法,这意味着它将方法添加到标准集合类中。
其中一种方法是toSet()
将集合转换为集合。总是返回一个新的集合,即使集合已经是一个集合。 示例用法: def结果= 1,2,2,2,3. Set ()断言结果实例集断言结果== 1,2,3作为Set
当你写这个时:
Set<String> unmodifiableFruits = Collections.unmodifiableCollection(fruits)它意味着一个.toSet()调用,强制unmodifiableCollection返回的Collection进入Set,隐式复制数据。
当你写这个时:
Set<String> unmodifiableFruits = Collections.unmodifiableSet(fruits)返回的值已经是Set,因此不调用toSet(),这意味着unmodifiableFruits和fruits共享数据。
这就是为什么在使用unmodifiableSet时必须通过添加new HashSet(...)显式地复制数据的原因。
在将集合传递给构造函数时,使用
Collections.unmodifiableCollection()是否是正确的方式?
绝对不是。使用unmodifiableCollection()并向Set分配,隐式调用复制数据的toSet,隐藏了一个副本被执行的事实。
为了确保代码的可读性,即任何阅读代码的人(包括3年后的自己)都会理解代码的作用,编写代码来显式地复制数据,使用复制构造函数。
当然,除非这是代码混淆的练习,否则这是一个很好的误导技巧。
https://stackoverflow.com/questions/52068311
复制相似问题