Collections.unmodifiableSet() 在 Java 中做了什么?

2022-09-01 04:08:52

我可以看到 Collections.unmodifiableSet 返回给定集合的不可修改视图,但我不明白为什么我们不能只使用修饰符来实现这一点。final

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

我们为什么需要?Collections.unmodifiableSet


答案 1

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

private final Foo something = new Foo();

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

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

因此,以下内容:

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

不会创建无法添加或以其他方式更改的;它只是意味着只会引用该实例。Setfixed

相比之下,做:

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

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

为了完整性:

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

创建一个不允许更改其内部状态的实例,并且还意味着它只会指向该集合的实例。Setfixed

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

private final int ANSWER = 42;

的值是 42。由于无法更改,因此它只能具有值 42。ANSWERANSWER

模糊所有线条的一个例子是这样的:

private final String QUESTION = "The ultimate question";

根据上述规则,包含表示“最终问题”的实例的地址,并且该地址无法更改。这里要记住的是,它本身是不可变的 - 你不能对更改它的实例做任何事情,任何本来会这样做的操作(例如,等)都会返回对完全不同的实例的引用。QUESTIONStringStringStringreplacesubstringString


答案 2

final仅保证对变量表示的对象的引用不能更改,它不会对对象的实例及其可变性执行任何操作。

final Set s = new Set();只是保证你不能再做了。它不会使集合不可修改,如果确实如此,则一开始就无法添加任何内容。因此,要使其真正清楚,仅影响变量引用,而不影响引用指向的对象。s = new Set();final

我可以执行以下操作:

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

但我不能这样做。

l = new ArrayList<String>();

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

您必须执行以下三项操作之一才能使集合容器线程安全。

java.util.Collections.syncronizedXXX();

java.util.Collections.unmodifiableXXX();

或者使用 中的相应容器之一。java.util.concurrency.* package

如果我有一个对象并且这样做了,这意味着我无法重新分配指向另一个对象。我还可以做Personfinal Person p = new Person("me");pPersonp.setFirstName("you");

令人困惑的是

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

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


推荐