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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:22:43  来源:igfitidea点击:

What does Collections.unmodifiableSet() do in Java?

javafinalunmodifiable

提问by Roman

I can see that Collections.unmodifiableSetreturns an unmodifiable view of the given set but I don't understand why we can't just use the finalmodifier to accomplish this.

我可以看到它Collections.unmodifiableSet返回给定集合的不可修改视图,但我不明白为什么我们不能只使用final修饰符来完成此操作。

In my understanding, finaldeclares 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

finaldeclares an object reference that can't be modified, e.g.

final声明一个不能修改的对象引用,例如

private final Foo something = new Foo();

creates a new Fooand places the reference in something. Thereafter, it's not possible to alter somethingto 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 Foothere are accessible to the relevant scope. If one or more of those methods modifies the internal state of that object, then finalwon't prevent that.

这并不能防止对象的内部状态的修改。我仍然可以调用Foo相关范围可访问的任何方法。如果这些方法中的一个或多个修改了该对象的内部状态,则final不会阻止它。

As such, the following:

因此,以下内容:

private final Set<String> fixed = new HashSet<String>();

does notcreate a Setthat can't be added to or otherwise altered; it just means that fixedwill only ever reference that instance.

没有创建一个Set不能被添加到或以其他方式改变; 它只是意味着fixed只会引用该实例。

By contrast, doing:

相比之下,这样做:

private Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );

creates an instance of a Setwhich will throw UnsupportedOperationExceptionif 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它将抛出一个实例,例如 - 对象本身将保护其内部状态并防止它被修改。UnsupportedOperationExceptionfixed.add()fixed.remove()

For completeness sake:

为了完整起见:

private final Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );

creates an instance of a Setwhich won't allow its internal state to be changed, and also means that fixedwill only ever point to an instance of that set.

创建一个 a 的实例,Set它不允许更改其内部状态,也意味着它fixed只会指向该集合的一个实例。

The reason that finalcan be used to create constants of primitives is based on the fact that the value can't be changed. Remember that fixedabove 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 ANSWERis that 42. Since ANSWERcan'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, QUESTIONcontains the address of an instance of Stringwhich represents "The ultimate question", and that address can't be changed. The thing to remember here is that Stringitself is immutable - you can't do anything to an instance of Stringwhich 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从而改变它,否则这样做的任何操作(如replacesubstring等)返回引用的完全不同的情况String

回答by Roman

finalonly 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, finalonly 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 finalI 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 Personobject and did final Person p = new Person("me");it means I can't reassign pto point to another Personobject. 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 constin 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 constjust the referenceto those objects are finaland can't be reassigned to referenceanother object.

看起来像const在 C++ 中,实际上它们指向的对象本质上是不可变/不可修改的。具有可以改变对象内部状态的 mutator 方法的容器或对象const不仅仅是对这些对象的引用final并且不能重新分配以引用另一个对象。

回答by Chris Jester-Young

finalis 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 finalreference.

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 actualSetinto unmodifiable set and assigned to new reference(wrapperSet).

放入actualSet不可修改的集合并分配给新的引用(wrapperSet)。

Set<String> wrapperSet=Collections.unmodifiableSet(orginalSet);

Print the wrapperSet. so it will have actualSetValues

打印 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 actualSetand 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.

打印actualSetwrapperSet。两组值相同。因此,如果您在实际集合上添加/删除任何元素,则更改也将反映在包装器集合上。

    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