Collections.unmodificSet() 在 Java 中做什么?

发布于 2024-08-24 06:06:51 字数 399 浏览 11 评论 0原文

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

根据我的理解,final 声明了一个常量:无法修改的东西。因此,如果一个集合被声明为常量,那么它就不能被修改:不能从集合中删除任何内容,也不能添加任何内容。

为什么我们需要Collections.unmodifyingSet

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.

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.

Why do we need Collections.unmodifiableSet?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

绝不放开 2024-08-31 06:06:51

final 声明一个无法修改的对象引用,例如

private final Foo something = new Foo();

创建一个新的Foo 并将该引用放置在something 中。此后,无法更改 something 以指向 Foo 的不同实例。

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

因此,以下内容:

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

是否创建一个无法添加或以其他方式更改的Set?它只是意味着 fixed 将仅引用该实例。

相比之下,执行以下操作:

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

创建一个 Set 实例,如果尝试调用 fixed.add(),它将抛出 UnsupportedOperationException例如,fixed.remove() - 对象本身将保护其内部状态并防止其被修改。

为了完整起见:

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

创建一个 Set 实例,该实例不允许更改其内部状态,并且也意味着 fixed 只会指向该实例放。

final 之所以可以用来创建基元常量,是基于其值无法更改的事实。请记住,上面的 fixed 只是一个引用 - 一个包含无法更改的地址的变量。好吧,对于原语,例如

private final int ANSWER = 42;

ANSWER 的值是 42。由于 ANSWER 无法更改,因此它的值永远只有 42。

这个例子模糊了所有内容这些行将是这样的:

private final String QUESTION = "The ultimate question";

根据上述规则,QUESTION 包含代表“终极问题”的 String 实例的地址,并且该地址无法更改。这里要记住的是,String 本身是不可变的 - 您不能对 String 的实例执行任何更改它的操作,也不能执行任何其他操作(例如 replacesubstring 等)返回对完全不同的 String 实例的引用。

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

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.

This does not prevent 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.

As such, the following:

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

does not create a Set that can't be added to or otherwise altered; it just means that fixed will only ever reference that instance.

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.

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.

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.

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.

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.

夜唯美灬不弃 2024-08-31 06:06:51

final 仅保证对变量所代表的对象的引用不能更改,它对对象的实例及其可变性没有任何作用。

final Set s = new Set(); 只是保证您不能再次执行 s = new Set(); 。它不会使集合不可修改,如果是的话,您一开始就无法向其中添加任何内容。因此,为了明确起见,final 仅影响变量 reference,而不影响引用指向的对象。

我可以执行以下操作:

final List<String> l = new ArrayList<String>();
l.add("hello");
l.add("world");
l.remove(0);

但我不能执行此操作。

l = new ArrayList<String>();

再次因为 final 我无法修改变量 l 指向的内容。

您必须执行以下三件事之一才能使 Collection 容器线程安全。

java.util.Collections.syncronizedXXX();

java.util.Collections.unmodifiableXXX();


使用 java.util.concurrency.* 包中的适当容器之一。

如果我有一个 Person 对象并执行了 final Person p = new Person("me"); 这意味着我无法将 p 重新分配给指向另一个 Person 对象。我仍然可以做 p.setFirstName("you");

令人困惑的是,它

final int PI = 3.14;
final String greeting = "Hello World!";

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

final only guarantees that the reference to the object the variable represents can't be changed it doesn't do anything for the instance of the object and its mutability.

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 reference not the object the reference points to.

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.

you have to do one of the following three things to make a Collection container thread safe.

java.util.Collections.syncronizedXXX();

or

java.util.Collections.unmodifiableXXX();

or
use one of the appropriate containers from 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");

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 reference to those objects are final and can't be reassigned to reference another object.

涙—继续流 2024-08-31 06:06:51

Collections.unmodifyingSet(Set) 将在原始集合上创建包装器。该包装器集无法修改。但原始设置仍然可以修改。

示例:

 Set<String> actualSet=new HashSet<String>(); //Creating set

添加一些元素

actualSet.add("aaa");
actualSet.add("bbb");

打印添加的元素

System.out.println(actualSet);   //[aaa, bbb]

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

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

打印包装器集。因此它将具有 actualSet 值,

System.out.println(wrapperSet);   //[aaa, bbb]

让我们尝试在 wrapperSet 上删除/添加一个元素。

wrapperSet.remove("aaa");   //UnSupportedOperationException 

中添加一个元素

    actualSet .add("ccc");

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

    System.out.println(actualSet);  //[aaa, ccc, bbb]
    System.out.println(wrapperSet);  // [aaa, ccc, bbb]

用法:

Collections.unmodifyingSet(Set)用于防止修改任何对象的 Set 的 getter 方法。让我们说

public class Department{

    private Set<User> users=new HashSet<User>();

    public Set<User> getUsers(){
        return Collections.unmodifiableSet(users); 
    }
}

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.

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).

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

Print the wrapperSet. so it will have actualSet Values

System.out.println(wrapperSet);   //[aaa, bbb]

lets try to remove/add one element on wrapperSet.

wrapperSet.remove("aaa");   //UnSupportedOperationException 

Add one more element in 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.

    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

public class Department{

    private Set<User> users=new HashSet<User>();

    public Set<User> getUsers(){
        return Collections.unmodifiableSet(users); 
    }
}
无名指的心愿 2024-08-31 06:06:51

final 不是(C++ 风格)const。与 C++ 不同,Java 没有 const 方法或类似的东西,可以通过 Final 引用调用可以更改对象的方法。

Collections.unmodifying* 是一个包装器,它强制(仅在运行时,而不是在编译时)相关集合的只读性。

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.

Collections.unmodifiable* is a wrapper that enforces (at run time only, not at compile time) the read-only-ness for the collection concerned.

深海不蓝 2024-08-31 06:06:51

总结一下我们能做和不能做的:

准备工作:

private Set<String> words = new HashSet<>(Arrays.asList("existing word"));

通过引用最终

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

可以

words.add("new word");

不能

words = new HashSet<>(); //compilation error

通过引用最终,并且不能通过集合修改。

私人最终设置单词= Collections.unmodifyingSet(单词);

can

String word = words.iterator().next();

不能

words = new HashSet<>(); // compilation error
words.add("new word"); // runtime error UnsupportedOperationException

cant:通过引用最终确定,

被集合修改,但作为集合的对象是可变的。 但是如果您有 mutual< 的集合/a> 对象,您可以更改该对象的内部状态。

 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)));

还是不能

set = new HashSet<>(); // compilation error
set.add(new A(777)); // runtime error UnsupportedOperationException

但是可以

 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

 

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);

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 mutable as collection's object.

But if you have the collection with mutual objects 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

 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文