我可以看到Collections.unmodifiableSet
返回给定集的不可修改视图,但我不明白为什么我们不能只使用final
修改器来实现此目的。Collections.unmodifiableSet()在Java中做什么?
在我的理解中,final
声明了一个常量:无法修改的东西。所以,如果一个集合被声明为一个常量,那么它就不能被修改:任何东西都不能被删除,也不能添加任何东西。我们需要Collections.unmodifiableSet
?
我可以看到Collections.unmodifiableSet
返回给定集的不可修改视图,但我不明白为什么我们不能只使用final
修改器来实现此目的。Collections.unmodifiableSet()在Java中做什么?
在我的理解中,final
声明了一个常量:无法修改的东西。所以,如果一个集合被声明为一个常量,那么它就不能被修改:任何东西都不能被删除,也不能添加任何东西。我们需要Collections.unmodifiableSet
?
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
的一个实例,它会抛出UnsupportedOperationException
如果试图调用fixed.add()
或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
的一个实例进行任何修改,并且任何其他操作(如replace
,substring
等)都会返回对完全不同的引用String
的实例。
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);
,但我不能这样做。因为final
我不能修改变量l指向什么。
您必须执行以下三件事之一才能使Collection容器线程安全。
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!";
样子const
在C++中,而事实上它们指向的对象是不可改变/不可改变的天性。具有可以改变对象内部状态的增变器方法的容器或对象不是const
只是参考那些对象是final
并且不能被重新分配到参考另一个对象。
final
不是(C++风格)const
。与C++不同,Java没有const
-方法或类似的东西,可以通过final
引用来调用可以更改对象的方法。
Collections.unmodifiable*
是一个包装,它强制(仅在运行时,不在编译时)为相关集合设置只读属性。
的Collections.unmodifiableSet(Set<? extends T>)
将在原来设置创建包装。这个包装套件不能被修改。但仍然可以修改原始设置。
实施例:
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");
打印actualSet
和wrapperSet
再添加一个元素。两组值都相同。所以如果您添加/删除实际设置中的任何元素,则更改也会反映在包装设置上。
System.out.println(actualSet); //[aaa, ccc, bbb]
System.out.println(wrapperSet); // [aaa, ccc, bbb]
用法:
这Collections.unmodifiableSet(Set<? extends T>)
用于防止任何对象的设置的吸气剂的方法的修饰。让说
public class Department{
private Set<User> users=new HashSet<User>();
public Set<User> getUsers(){
return Collections.unmodifiableSet(users);
}
}
好贴。总之,_reference_不能改变,但是对象的_contents_可以*。 – extraneon 2010-03-10 20:20:35