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!";
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
5条答案
按热度按时间jmp7cifd1#
final
声明了一个不能修改的对象引用,例如创建一个新的
Foo
并将引用放置在something
中。此后,就不可能更改something
以指向Foo
的不同示例。这并不阻止修改对象的内部状态。我仍然可以调用
Foo
上的任何方法,这些方法可以访问相关的范围。如果这些方法中的一个或多个修改了该对象的内部状态,那么final
不会阻止这种情况。因此,以下内容:
不会创建一个不能添加或更改的
Set
;它只是意味着fixed
将只引用该示例。相比之下,做:
创建一个
Set
的示例,如果试图调用fixed.add()
或fixed.remove()
,它将抛出UnsupportedOperationException
,例如-对象本身将保护其内部状态并防止其被修改。为完整起见:
创建了一个
Set
的示例,它不允许改变它的内部状态,也意味着fixed
将只指向该集合的一个示例。final
可用于创建基元常量的原因是基于值不能更改的事实。请记住,上面的fixed
只是一个引用-一个包含不能更改的地址的变量。那么,对于原语,例如ANSWER
的值是42。因为ANSWER
不能被改变,所以它的值只有42。模糊所有线条的示例如下:
根据上面的规则,
QUESTION
包含了String
的一个示例的地址,它代表了“终极问题”,并且这个地址不能被改变。这里需要记住的是,String
本身是不可变的-您不能对String
的示例做任何改变它的操作,并且任何其他操作(例如replace
,substring
等)都会返回对String
的完全不同示例的引用。dzhpxtsq2#
final
只保证变量所代表的对象的引用不能被改变,它不会对对象的示例及其可变性做任何事情。final Set s = new Set();
只是保证你不能再做s = new Set();
。它并没有使集合不可修改,如果这样做了,你就不能在开始时向它添加任何东西。因此,为了让它真正清楚,final
只影响变量reference,而不是引用指向的对象。我可以执行以下操作:
但我做不到
同样因为
final
我不能修改变量l指向什么。你必须做以下三件事之一,使集合容器线程安全。
或
或者使用
java.util.concurrency.* package
中的适当容器之一。如果我有一个
Person
对象,并做了final Person p = new Person("me");
,这意味着我不能重新分配p
指向另一个Person
对象。我还能做p.setFirstName("you");
令人困惑的是
看起来像C++中的
const
,而实际上它们指向的对象本质上是不可变/不可修改的。容器或对象的mutator方法可以改变对象的内部状态,而不是const
,只是这些对象的reference是final
,不能重新分配给reference另一个对象。4ioopgfo3#
Collections.unmodifiableSet(Set<? extends T>)
将在原始集合上创建 Package 器。无法修改此 Package 集。但是仍然可以修改原始集合。示例:
添加一些元素
打印添加的元素
将
actualSet
放入不可修改的集合中,并分配给新的引用(wrapperSet
)。打印wrapperSet。因此它将具有
actualSet
值让我们尝试在
wrapperSet
上删除/添加一个元素。在
actualSet
中再添加一个元素打印
actualSet
和wrapperSet
。两组值相同。所以如果你在actual set上添加/删除任何元素,这些变化也会反映在wrapper set上。用法:
这个
Collections.unmodifiableSet(Set<? extends T>)
用于防止修改任何对象的Set的getter方法。让说2vuwiymt4#
final
不是(C风格)const
。与C不同,Java没有const
-方法或类似的东西,可以通过final
引用调用可以更改对象的方法。Collections.unmodifiable*
是一个 Package 器,它强制(仅在运行时,而不是在编译时)相关集合的只读性。jgwigjjp5#
总结一下我们能做和不能做的:
制备:
最终引用
可以:
不能:
引用为final,集合不可修改。
public int findDuplicate(int findDuplicate);
可以:
不能:
Final通过引用,集合不可修改,但作为集合的对象是可变的。
但是如果你有一个包含mutual对象的集合,你可以改变这个对象的内部状态。
还是不能
但能否