Collections.unmodifiableSet() 在 Java 中有什么作用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2420096/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What does Collections.unmodifiableSet() do in Java?
提问by Roman
I can see that Collections.unmodifiableSet
returns an unmodifiable view of the given set but I don't understand why we can't just use the final
modifier to accomplish this.
我可以看到它Collections.unmodifiableSet
返回给定集合的不可修改视图,但我不明白为什么我们不能只使用final
修饰符来完成此操作。
In my understanding, final
declares a constant: something that cannot be modified. So, if a set is declared as a constant then it cannot be modified: nothing can be removed from the set and nothing can be added.
在我的理解中,final
声明了一个常量:无法修改的东西。所以,如果一个集合被声明为一个常量,那么它就不能被修改:不能从集合中删除任何东西,也不能添加任何东西。
Why do we need Collections.unmodifiableSet
?
我们为什么需要Collections.unmodifiableSet
?
采纳答案by Rob
final
declares an object reference that can't be modified, e.g.
final
声明一个不能修改的对象引用,例如
private final Foo something = new Foo();
creates a new Foo
and places the reference in something
. Thereafter, it's not possible to alter something
to point to a different instance of Foo
.
创建一个新的Foo
并将引用放在something
. 此后,无法更改something
为指向Foo
.
This does notprevent modification of the internal state of the object. I can still call whatever methods on Foo
there are accessible to the relevant scope. If one or more of those methods modifies the internal state of that object, then final
won't prevent that.
这并不能防止对象的内部状态的修改。我仍然可以调用Foo
相关范围可访问的任何方法。如果这些方法中的一个或多个修改了该对象的内部状态,则final
不会阻止它。
As such, the following:
因此,以下内容:
private final Set<String> fixed = new HashSet<String>();
does notcreate a Set
that can't be added to or otherwise altered; it just means that fixed
will only ever reference that instance.
并没有创建一个Set
不能被添加到或以其他方式改变; 它只是意味着fixed
只会引用该实例。
By contrast, doing:
相比之下,这样做:
private Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
creates an instance of a Set
which will throw UnsupportedOperationException
if one attempts to call fixed.add()
or fixed.remove()
, for example - the object itself will protect its internal state and prevent it from being modified.
创建一个 a 的实例,如果尝试调用or ,Set
它将抛出一个实例,例如 - 对象本身将保护其内部状态并防止它被修改。UnsupportedOperationException
fixed.add()
fixed.remove()
For completeness sake:
为了完整起见:
private final Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
creates an instance of a Set
which won't allow its internal state to be changed, and also means that fixed
will only ever point to an instance of that set.
创建一个 a 的实例,Set
它不允许更改其内部状态,也意味着它fixed
只会指向该集合的一个实例。
The reason that final
can be used to create constants of primitives is based on the fact that the value can't be changed. Remember that fixed
above was just a reference - a variable containing an address that can't be changed. Well, for primitives, e.g.
final
可以用于创建基元常量的原因是基于值无法更改的事实。请记住,fixed
上面只是一个引用 - 一个包含无法更改的地址的变量。好吧,对于原语,例如
private final int ANSWER = 42;
the value of ANSWER
is that 42. Since ANSWER
can't be changed, it will only ever have the value 42.
的值ANSWER
是 42。由于ANSWER
无法更改,因此它将永远只有值 42。
An example that blurs all the lines would be this:
一个模糊所有线条的例子是这样的:
private final String QUESTION = "The ultimate question";
Per the rules above, QUESTION
contains the address of an instance of String
which represents "The ultimate question", and that address can't be changed. The thing to remember here is that String
itself is immutable - you can't do anything to an instance of String
which changes it, and any operations which would otherwise do so (such as replace
, substring
, etc.) return references to entirely different instances of String
.
根据上述规则,QUESTION
包含String
代表“终极问题”的实例的地址,并且该地址不能更改。这里要记住的一点是,String
本身是不可变的-你不能做任何事情的一个实例,String
从而改变它,否则这样做的任何操作(如replace
,substring
等)返回引用的完全不同的情况String
。
回答by Roman
final
only guarantees that the referenceto the object the variable represents can't be changed it doesn't do anything for the instance of the object and its mutability.
final
仅保证对变量所代表的对象的引用无法更改,它不会对对象的实例及其可变性做任何事情。
final Set s = new Set();
just guarantees you can't do s = new Set();
again. It doesn't make the set unmodifiable, it if did you couldn't add anything to it to begin with. So to make it really clear, final
only affects the variable referencenot the object the reference points to.
final Set s = new Set();
只是保证你不能再做s = new Set();
。它不会使该集合不可修改,如果您一开始就无法向其添加任何内容。所以要说清楚,final
只影响变量引用,而不影响引用指向的对象。
I can do the following:
我可以执行以下操作:
final List<String> l = new ArrayList<String>();
l.add("hello");
l.add("world");
l.remove(0);
but I can't do this.
但我不能这样做。
l = new ArrayList<String>();
again because of the final
I can't modify what the variable l points to.
再次因为final
我无法修改变量 l 指向的内容。
you have to do one of the following three things to make a Collection container thread safe.
您必须执行以下三件事之一才能使 Collection 容器线程安全。
java.util.Collections.syncronizedXXX();
or
或者
java.util.Collections.unmodifiableXXX();
or
use one of the appropriate containers from java.util.concurrency.* package
.
或使用来自 的适当容器之一java.util.concurrency.* package
。
if I had a Person
object and did final Person p = new Person("me");
it means I can't reassign p
to point to another Person
object. I can still do p.setFirstName("you");
如果我有一个Person
对象并且做了final Person p = new Person("me");
这意味着我不能重新分配p
指向另一个Person
对象。我还能做p.setFirstName("you");
What confuses the situation is that
令人困惑的是,
final int PI = 3.14;
final String greeting = "Hello World!";
look like const
in C++, when in fact the objects that they point to are immutable/unmodifiable by nature. Containers or objects with mutator methods that can alter the internal state of the object are not const
just the referenceto those objects are final
and can't be reassigned to referenceanother object.
看起来像const
在 C++ 中,实际上它们指向的对象本质上是不可变/不可修改的。具有可以改变对象内部状态的 mutator 方法的容器或对象const
不仅仅是对这些对象的引用,final
并且不能重新分配以引用另一个对象。
回答by Chris Jester-Young
final
is not (C++-style) const
. Unlike C++, Java does not have const
-methods or anything like that, and methods that can change the object can be called via a final
reference.
final
不是 (C++-style) const
。与 C++ 不同,Java 没有const
-methods 或类似的东西,并且可以通过final
引用调用可以更改对象的方法。
Collections.unmodifiable*
is a wrapper that enforces (at run time only, not at compile time) the read-only-ness for the collection concerned.
Collections.unmodifiable*
是一个包装器,它强制(仅在运行时,而不是在编译时)相关集合的只读性。
回答by MADHAIYAN M
The Collections.unmodifiableSet(Set<? extends T>)
will create wrapper on the original set. This wrapper set can not be modified. but still the original set can be modified.
该Collections.unmodifiableSet(Set<? extends T>)
会在原来设置创建包装。无法修改此包装器集。但仍然可以修改原始设置。
Example:
例子:
Set<String> actualSet=new HashSet<String>(); //Creating set
Adding some elements
添加一些元素
actualSet.add("aaa");
actualSet.add("bbb");
Printing added elements
打印添加的元素
System.out.println(actualSet); //[aaa, bbb]
Put the actualSet
into unmodifiable set and assigned to new reference(wrapperSet
).
放入actualSet
不可修改的集合并分配给新的引用(wrapperSet
)。
Set<String> wrapperSet=Collections.unmodifiableSet(orginalSet);
Print the wrapperSet. so it will have actualSet
Values
打印 wrapperSet。所以它会有actualSet
值
System.out.println(wrapperSet); //[aaa, bbb]
lets try to remove/add one element on wrapperSet
.
让我们尝试在 上删除/添加一个元素wrapperSet
。
wrapperSet.remove("aaa"); //UnSupportedOperationException
Add one more element in actualSet
再添加一个元素 actualSet
actualSet .add("ccc");
Print actualSet
and wrapperSet
. both sets values are same. so If you add/remove any elements on actual set the changes will be reflected on wrapper set as well.
打印actualSet
和wrapperSet
。两组值相同。因此,如果您在实际集合上添加/删除任何元素,则更改也将反映在包装器集合上。
System.out.println(actualSet); //[aaa, ccc, bbb]
System.out.println(wrapperSet); // [aaa, ccc, bbb]
Usage:
用法:
This Collections.unmodifiableSet(Set<? extends T>)
is used to prevent modification of Set's getter method of any object. let say
这 Collections.unmodifiableSet(Set<? extends T>)
用于防止修改任何对象的 Set 的 getter 方法。让说
public class Department{
private Set<User> users=new HashSet<User>();
public Set<User> getUsers(){
return Collections.unmodifiableSet(users);
}
}
回答by Novdar
Summarize that we can do and can't:
总结一下我们能做和不能做的:
Preparation:
准备:
private Set<String> words = new HashSet<>(Arrays.asList("existing word"));
Final by reference
最终参考
private final Set<String> words = new HashSet<>();
can:
可以:
words.add("new word");
can't:
不能:
words = new HashSet<>(); //compilation error
Final by reference and unmodifiable by collection.
最终通过引用和不可修改的集合。
private final Set words = Collections.unmodifiableSet(words);
private final Set words = Collections.unmodifiableSet(words);
can:
可以:
String word = words.iterator().next();
can't:
不能:
words = new HashSet<>(); // compilation error
words.add("new word"); // runtime error UnsupportedOperationException
Final by reference and unmodifiable by collection but mutual as collection's object.
最终通过引用并且不可被集合修改,但作为集合的对象是相互的。
Butif you have the collection with mutualobjects you can CHANGE the inner state of that object.
但是,如果您拥有包含相互对象的集合,则可以更改该对象的内部状态。
class A {
public int a; //mutable field. I can change it after initialization
public A(int a) {this.a = a;}
}
private final Set<A> set = Collections.unmodifiableSet(Arrays.asList(new A(25)));
Still can't
还是不能
set = new HashSet<>(); // compilation error
set.add(new A(777)); // runtime error UnsupportedOperationException
But can
但是可以
A custom = words.iterator().next(); //here custom.a = 25;
custom.a = 777; //here first element of **final, unmodifible** collection
//was changed from 25 to 777