Collections.unmodifiableMap源码解析
其实还有unmodifiableList,unmodifiableSet两个相似的方法,接下来就分析一下。
unmodifiable的中文意思是:不可更改,不可修改的。
接下来我们来看看此处的unmodifiableMap和我们平常使用的map有什么不同。
public class UnmodifiableMapTest {
@Test
public void testUnmodifiableMap() {
//我们平常使用的hashMap
Map<String, Object> generalMap = new HashMap<>();
//我们平常都这么用
generalMap.put("i'm generalMap", "bling");
//调用Collections的静态方法返回了一个unmodifiableMap
Map<String, Object> unmodifiableMap = Collections.unmodifiableMap(generalMap);
//我们继续往map里塞值
unmodifiableMap.put("i'm unmodifiableMap", "kkk");
}
}
我们运行一下,
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableMap.put(Collections.java:1457)
at cn.magfin.devastator.UnmodifiableMapTest.testUnmodifiableMap(UnmodifiableMapTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
可以看到当我们想要往unmodifiableMap里继续塞值的时候抛出了一个异常,不被支持的操作!
我们接下来来看一下,这个unmodifiableMap静态方法里面到底做了什么处理:
public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
return new UnmodifiableMap<>(m);
}
这里创建了一个新的UnmodifiableMap,并且使用我们原先创建的普通的map作为构造参数,我们继续往下:
private final Map<? extends K, ? extends V> m;
UnmodifiableMap(Map<? extends K, ? extends V> m) {
if (m==null)
throw new NullPointerException();
this.m = m;
}
这里简单的对参数进行了判空防止产生NPE,随后将我们的map赋给了一个由final修饰的变量m并且作为我们先前调用的静态方法unmodifiableMap的返回值.
到这里还是不能解释为什么我们调用put方法的时候会抛出异常.我们接着往下看当我们调用put的时候发生了什么事情.
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
可以看到,当我们直接使用unmodifiableMap的put方法的时候,直接抛出了一个UnsupportedOperationException异常.
public boolean isEmpty() {return m.isEmpty();}
public boolean containsKey(Object key) {return m.containsKey(key);}
public boolean containsValue(Object val) {return m.containsValue(val);}
public V get(Object key) {return m.get(key);}
当我们调用unmodifiableMap.get(key)方法的时候,就变相的调用了我们原先的map的get(key)方法,并且还有其他几个map相关的操作方法都是这么实现的.
最后补充说明:
final Map<String, Object> finalMap = new HashMap<>();
Map<String, Object> unmodifiableMap = Collections.unmodifiableMap(generalMap);
此处的finalMap != unmodifiableMap,这两者是没有任何关系的,前者是不能重新更改对象引用的,但是后者完全不受影响,你完全可以更改unmodifiableMap的引用,比如:
Map<String, Object> unmodifiableMap = new hashMap<>();
但是如此一来这个"新的"unmodifiableMap已经不再具有unmodifiable的特性了!