Collections.unmodifiableMap,Collections.unmodifiableList,Collections.unmodifiableSet作用及源码解析
在文章:mybatis源码解析,一步一步从浅入深(五):mapper节点的解析中mybatis的源码中用到了collections.unmodifiablelist方法,其实还有unmodifiablemap,unmodifiableset两个相似的方法,接下来就分析一下。
unmodifiablemap,unmodifiablelist,unmodifiableset都是collections的静态方法。可以明显看到三个方法都是unmodifiable开始的。
unmodifiable的中文意思是:不可更改,不可修改的。那么这三个方法到底有什么用呢?想必你已经有一个大概的猜测了。记住你的猜测,先来看一段代码:
一,使用示例
1 public void testunmodifiable() { 2 map map = new hashmap(); 3 map.put("name", "zhangchengzi"); 4 map.put("age", 20); 5 6 system.out.println("map before:"+map);//打印结果:map before:{name=zhangchengzi, age=20} 7 8 map unmodifiablemap = collections.unmodifiablemap(map); 9 system.out.println("unmodifiablemap before:"+unmodifiablemap);//打印结果:unmodifiablemap before:{name=zhangchengzi, age=20}。 10 11 system.out.println("年龄:"+unmodifiablemap.get("age"));//打印结果:年龄:20 12 //修改年龄 13 unmodifiablemap.put("age", 28); 14 15 system.out.println("map after:"+map); 16 system.out.println("unmodifiablemap after:"+unmodifiablemap); 17 }
相信你代码都看的很明白,那么后面两个为什么没有打印出结果呢?因为在13行抛出 了异常:
java.lang.unsupportedoperationexception at java.util.collections$unmodifiablemap.put(collections.java:1457) at com.test.learnmybatis.userdaotest.testunmodifiable(userdaotest.java:63) 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:497) at org.junit.runners.model.frameworkmethod$1.runreflectivecall(frameworkmethod.java:47) at org.junit.internal.runners.model.reflectivecallable.run(reflectivecallable.java:12) at org.junit.runners.model.frameworkmethod.invokeexplosively(frameworkmethod.java:44) at org.junit.internal.runners.statements.invokemethod.evaluate(invokemethod.java:17) at org.junit.runners.parentrunner.runleaf(parentrunner.java:271) at org.junit.runners.blockjunit4classrunner.runchild(blockjunit4classrunner.java:70) at org.junit.runners.blockjunit4classrunner.runchild(blockjunit4classrunner.java:50) at org.junit.runners.parentrunner$3.run(parentrunner.java:238) at org.junit.runners.parentrunner$1.schedule(parentrunner.java:63) at org.junit.runners.parentrunner.runchildren(parentrunner.java:236) at org.junit.runners.parentrunner.access$000(parentrunner.java:53) at org.junit.runners.parentrunner$2.evaluate(parentrunner.java:229) at org.junit.runners.parentrunner.run(parentrunner.java:309) at org.eclipse.jdt.internal.junit4.runner.junit4testreference.run(junit4testreference.java:86) at org.eclipse.jdt.internal.junit.runner.testexecution.run(testexecution.java:38) at org.eclipse.jdt.internal.junit.runner.remotetestrunner.runtests(remotetestrunner.java:538) at org.eclipse.jdt.internal.junit.runner.remotetestrunner.runtests(remotetestrunner.java:760) at org.eclipse.jdt.internal.junit.runner.remotetestrunner.run(remotetestrunner.java:460) at org.eclipse.jdt.internal.junit.runner.remotetestrunner.main(remotetestrunner.java:206)
那么unmodifiablemap方法的作用就是将一个map 进行包装,返回一个不可修改的map。如果调用修改方法就会抛出java.lang.unsupportedoperationexception异常。
同样的道理unmodifiablelist,unmodifiableset就是将一个list或则set进行包装,返回一个不可修改的list或者set。你猜对了吗?那么unmodifiablemap是怎么做到这些事情的呢?
二,unmodifiablemap方法源码解读:
上面提到过unmodifiablemap是collections工具类的一个静态方法:
/** * 返回一个指定map的不可修改的视图,这个方法返回的视图为用户提供内部map的"只读"访问, * 对是返回视图执行“读取”操作会直接作用到指定的map, * 同时如果对返回视图执行修改操作(不论是直接的还是间接的)都会返回异常:unsupportedoperationexception * returns an unmodifiable view of the specified map. this method * allows modules to provide users with "read-only" access to internal * maps. query operations on the returned map "read through" * to the specified map, and attempts to modify the returned * map, whether direct or via its collection views, result in an * <tt>unsupportedoperationexception</tt>.<p> * * 如果指定的map是可序列化的,则返回的map也将是可序列化的。 * the returned map will be serializable if the specified map * is serializable. * * @param <k> the class of the map keys * @param <v> the class of the map values * @param m the map for which an unmodifiable view is to be returned. * @return an unmodifiable view of the specified map. */ public static <k,v> map<k,v> unmodifiablemap(map<? extends k, ? extends v> m) { return new unmodifiablemap<>(m); }
看源码的注释已经做了解释说明,但是还没有涉及到具体“不可修改的”原理,我们接着看源码。这个collections.unmodifiablemap方法中,使用参数map 实例化了一个unmodifiablemap。我们看一下这个类:
1,unmodifiablemap类实现了map接口,并且在这个类中有一个final修饰的 map 类型的属性m。在构造方法中将调用collections.unmodifiablemap(map)方法中传入的map实参,赋值给了unmodifiablemap类的m属性。
2,上面在unmodifiablemap方法的注释中提到,对返回视图的修改,直接指向指定的map。为什么呢?看unmodifiablemap的get方法,可以清晰看到,get方法直接到用了m.get(key)方法。
3,同时最关键的是“不可修改”是怎么实现的。看unmodifiablemap的put方法,也可以很清晰的看到 在put方法中直接抛出了unsupportedoperationexception。
到这里collections.unmodifiablemap方法的分析就进行完了,总结一下collections.unmodifiablemap方法返回一个不可修改的map。
三,unmodifiablelist,unmodifiableset
unmodifiablelist,unmodifiableset的作用和实现原理和unmodifiablemap的是一样的,有兴趣就自己去看一下源码吧。
原创不易,转发请注明出处:https://www.cnblogs.com/zhangchengzi/p/9685918.html
更多干货,请参考: