Collections.unmodifiableMap
Posted smurf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Collections.unmodifiableMap相关的知识,希望对你有一定的参考价值。
1. Collections.unmodifiableMap 是什么?
Java的官方解释:
public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K,? extends V> m)
翻译过来就是:该方法返回了一个map的不可修改的视图umap, 为用户提供了一种生成只读容器的方法。如果尝试修改该容器umap, 将会抛出UnsupportedOperationException异常。
2. Collections.unmodifiableMap 能做什么?
在《重构-改善既有代码逻辑》一书中提到了封装集合的功能(Encapsulate Collection)。
我们在类中经常需要返回一个集合,比如mapA。如果直接返回成员变量mapA本身的话,相当于对外暴露了集合的引用,外部就可以随意修改该对象的集合,该对象可能对修改都一无所知,属性却发生了变化。
一种解决方法,就是将该集合修饰为private, 在返回集合的方法中采用Collections.unmodifiableMap(mapA),返回mapA的一个不可变的副本。且该方法要比我们自己去复制一个副本效率要高。
3. Collections.unmodifiableMap 构造的map真的不可修改吗?
遗憾的是该结论并不总是成立。对于map<key, value>中的内容value, unmodifiableMap仅仅保证的是它的引用不能被修改,如果value对应的是一个可变对象,那么该unmodifiableMap的内容还是可变的。见实例:
1 public class UnmodifiableMap { 2 3 public static void main(String[] args) { 4 5 Map<String, Student> map = new HashMap<String, Student>(); 6 Student tom = new Student("tom", 3); 7 map.put("tom", tom); 8 map.put("jerry", new Student("jerry", 1)); 9 10 Map<String, Student> unmodifiableMap = Collections.unmodifiableMap(map); 11 // unmodifiableMap.put("tom", new Student("tom", 11)); // tag1 12 tom.setAge(11); // tag2 13 System.out.println(unmodifiableMap); 14 } 15 16 } 17 18 // mutable 19 class Student { 20 private String name; 21 private int age; 22 23 public Student(String name, int age) { 24 this.name = name; 25 this.age = age; 26 } 27 28 public String getName() { 29 return name; 30 } 31 32 public void setName(String name) { 33 this.name = name; 34 } 35 36 public int getAge() { 37 return age; 38 } 39 40 public void setAge(int age) { 41 this.age = age; 42 } 43 44 @Override 45 public String toString() { 46 return "Student{" + 47 "name=‘" + name + ‘\‘‘ + 48 ", age=" + age + 49 ‘}‘; 50 } 51 }
代码中Student 对象是可变对象。在tag1处,尝试更换为另一个对象,引用发生了变化,会抛出UnsupportedOperationException异常。unmodifiableMap阻止了对其的修改
但如果引用不变,见tag2处,还是tom, 但对该对象内容作了修改,unmodifiableMap并未阻止该行为。unmodifiableMap的内容变为了
{jerry=Student{name=‘jerry‘, age=1}, tom=Student{name=‘tom‘, age=11}}
所以为了线程安全,在使用Collections.unmodifiableMap的同时,尽量让其中的内容实现为不可变对象。
以上是关于Collections.unmodifiableMap的主要内容,如果未能解决你的问题,请参考以下文章