Collections. unmodifiableSet()在Java中有什么作用?

v64noz0r  于 2023-06-28  发布在  Java
关注(0)|答案(5)|浏览(130)

我可以看到Collections.unmodifiableSet返回给定集合的不可修改的视图,但我不明白为什么我们不能使用final修饰符来完成这一点。
在我的理解中,final声明了一个常量:不能被改变的东西。因此,如果一个集合被声明为常量,那么它就不能被修改:不能从集合中删除任何内容,也不能添加任何内容。
为什么需要Collections.unmodifiableSet

jmp7cifd

jmp7cifd1#

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()fixed.remove(),它将抛出UnsupportedOperationException,例如-对象本身将保护其内部状态并防止其被修改。
为完整起见:

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的完全不同示例的引用。

dzhpxtsq

dzhpxtsq2#

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指向什么。
你必须做以下三件事之一,使集合容器线程安全。

java.util.Collections.syncronizedXXX();

java.util.Collections.unmodifiableXXX();

或者使用java.util.concurrency.* package中的适当容器之一。
如果我有一个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,只是这些对象的referencefinal,不能重新分配给reference另一个对象。

4ioopgfo

4ioopgfo3#

Collections.unmodifiableSet(Set<? extends T>)将在原始集合上创建 Package 器。无法修改此 Package 集。但是仍然可以修改原始集合。

示例:

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

打印wrapperSet。因此它将具有actualSet

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

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

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

actualSet中再添加一个元素

actualSet .add("ccc");

打印actualSetwrapperSet。两组值相同。所以如果你在actual set上添加/删除任何元素,这些变化也会反映在wrapper set上。

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

用法:

这个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); 
    }
}
2vuwiymt

2vuwiymt4#

final不是(C风格)const。与C不同,Java没有const-方法或类似的东西,可以通过final引用调用可以更改对象的方法。
Collections.unmodifiable*是一个 Package 器,它强制(仅在运行时,而不是在编译时)相关集合的只读性。

jgwigjjp

jgwigjjp5#

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

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

引用为final,集合不可修改。

public int findDuplicate(int findDuplicate);

可以

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

不能

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

Final通过引用,集合不可修改,但作为集合的对象是可变的。

但是如果你有一个包含mutual对象的集合,你可以改变这个对象的内部状态。

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

相关问题