我经常发现有人会使用双括号这个反模式来进行编程(也被称为
双括号初始化](http://stackoverflow.com/q/1958636/521799))。[Stack Overflow上刚刚又有一个:
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}}
你可能并不熟悉这个语法,其实很简单。这里只有两点需要注意的:
1. 我们通过下面这段代码创建了一个继承自HashMap的匿名类:
new HashMap() {
}
在该匿名类中,我们通过实例初始化器(instance initializer)来将这个HashMap的匿名子类进行初始化:
{
put("id", "1234");
}
这些初始化器其实就对应于构造方法里面的代码。
为什么说它是双括号反模式(Double Curly Braces Anti Pattern)?
说它是一个反模式主要出于三方面的原因:
1. 可读性
可读性是最次要的一个原因。尽管它使得程序编写变得更简单,并且看起来跟JSON中数据结构的初始化差不多:
{
"firstName" : "John"
, "lastName" : "Smith"
, "organizations" :
{
"0" : { "id", "1234" }
, "abc" : { "id", "5678" }
}
}
没错。
如果Java的List和Map类型能有集合字面量就实在是太好了。通过双括号来模拟的话总显得有点怪怪的,有什么不对劲。
不过这个就当作是个人喜好吧,我们先暂且搁下不谈,因为还有更重要的原因:
2. 一个实例,一种类型
通过一次双括号的初始化我们其实就已经创建了一个新类型了!通过这种方式所生成的每一个新map,都会隐式地创建了一个无法重复使用的新类型。如果仅用一次的话也无可厚非。但如果在一个大型的应用中到处都充斥着这种代码的话,无形中会给你的类加载器增加了许多负担,你的堆会持有着这些类的引用。不信么?编译下上述代码并查看下编译器的输出。大概会是这样的:
Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class
这里只有最外围的Test.class是有意义的。
不过这还不是最重要的问题。
3. 内存泄露!
最重要的问题就是匿名类所造成的。它们持有着外围实例的引用,这简直就是个定时ZHADAN。想像一下,你把这个看似NB的HashMap初始化放到一个EJB或者是一个很重的包含着这样的生命周期的对象里:
{% raw %}
public class ReallyHeavyObject {
// Just to illustrate...
private int[] tonsOfValues;
private Resource[] tonsOfResources;
// This method almost does nothing
public void quickHarmlessMethod() {
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
// Some more code here
}
}
{% endraw %}
这个ReallyHeavyObject类中有许多资源,当ReallyHeavyObject对象被垃圾回收掉时这些资源是需要尽快被释放掉的。不过调用quickHarmlessMethod()方法并不会造成什么影响,因为这个map很快就会被回收掉了。
好的。
我们假设另外一个开发人员,他重构了一下这个方法,返回了这个map,或者是map中的某一部分:
{% raw %}
public Map quickHarmlessMethod() {
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
return source;
}
{% endraw %}
这下问题就严重了!现在你把ReallyHeavyObject中的所有状态都暴露给外部了,因为每个内部类都会持有一个外围实例的引用,也就是ReallyHeavyObject实例。不信么?运行下这段程序看看:
public static void main(String[] args) throws Exception {
Map map = new ReallyHeavyObject().quickHarmlessMethod();
Field field = map.getClass().getDeclaredField("this$0");
field.setAccessible(true);
System.out.println(field.get(map).getClass());
}
它会返回:
class ReallyHeavyObject
确实是这样!。如果你仍不相信的话,还可以使用调试器来查看下这个返回的map的内部状态。
你会发现外围实例的引用就在这个匿名的HashMap子类中安静地躺着。所有的这些匿名子类型都会持有一个这样的引用。
因此,不要使用这个反模式
你可能会说,如果将quickHarmlessMethod()声明成static的不就好了,这不会出现3中的泄露问题了,你说的没错。
不过上述代码中最糟糕的问题就是即便你知道这个静态上下文中的map该如何使用,但下一个开发人员可能会注意不到,他还可能会把这个static重构或者删除掉。他们还可能会把这个map存储在一个单例中,这样你就很难再从代码中看出哪里会有一个无用的ReallyHeavyObject的引用。
内部类是一头野兽。它已经造成过许多的问题以及认知失衡。匿名内部类则更为严重,因为读到这段代码的人可能完全没有意识到自己已经包装了一个外围实例,并且把这个实例传递到了别处。
结论便是:
不要自作聪明了,别使用双括号来进行初始化。
原创文章转载请注明出处:
http://it.deepinmind.com
英文原文链接
分享到:
相关推荐
基于MVC设计思想和QT开发的五子棋游戏源码+项目说明(支持双人模式和人机模式).zip基于MVC设计思想和QT开发的五子棋游戏源码+项目说明(支持双人模式和人机模式).zip基于MVC设计思想和QT开发的五子棋游戏源码+项目...
因此,练习如何用简洁明了的语言表达复杂的想法,同时保持自然和诚恳的态度,能有效避免模式化答题带来的负面效果。 总的来说,结构化面试并非简单的记忆和复述,而是展示个人能力和思维方式的过程。求职者应注重...
西工大老师讲课用的模式识别PPT,仅供学习参考,切勿未经授权,拿来教学使用!
在公务员面试中,答题策略和方式至关重要,但考生往往容易陷入模式化答题的陷阱,这在面试中是非常不利的。面试的目的是考察考生的真实思维能力、问题解决能力和个人特质,而非机械地复述预设答案。因此,考生应避免...
Java课程设计-基于MVC模式设计模式实现的留言本程序源码.zipJava课程设计-基于MVC模式设计模式实现的留言本程序源码.zipJava课程设计-基于MVC模式设计模式实现的留言本程序源码.zipJava课程设计-基于MVC模式设计模式...
MFC贪吃蛇游戏分享,该项目具有:暂停/继续、自动游戏、双人模式等功能+源代码+文档说明 - 小白不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源...
3. **dex2jar**:这个工具能把DEX文件转换为JAR文件,然后可以用Java的反编译工具(如JD-GUI或JADX)进一步处理。 4. **FRIDA**:这是一个动态代码插桩工具,可以在运行时查看和修改应用程序的行为,对于理解和调试...
Java开发基于MVC设计模式的购物车项目源码+项目说明.zipJava开发基于MVC设计模式的购物车项目源码+项目说明.zipJava开发基于MVC设计模式的购物车项目源码+项目说明.zipJava开发基于MVC设计模式的购物车项目源码+项目...
5. **游戏诈骗识别**:对于网络游戏中的优惠或赠品,要保持理智,切勿轻信“扫码转账返利”等活动,避免经济损失。 6. **电话伪装骗局**:遇到声称是熟人但要求转账的情况,要通过已知渠道验证对方身份,不可盲目...
信息安全课程设计-分析网站的反爬虫策略进行反反爬虫项目python源码 - 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,...
基于MVC模式+状态设计模式的物联网气体检测项目源码+项目说明文档.zip个人大三的课程作业、经导师指导并认可通过的高分设计项目,评审分96.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习...
切勿合闸标志将变压器恢复供电.pptx
Java反编译工具是开发者和逆向工程人员用于查看Java字节码并将其转换回源代码的工具。本文将深入探讨Java反编译工具JAD,包括它的32位和64位版本,并提供基本的使用说明。 **一、什么是JAD?** JAD(Java ...
上马电动汽车,切勿盲目乐观.pdf
学习网站结构优化切勿捡了芝麻丢了西瓜.ppt
本资源集合提供了深入分析和实践操作木马隐藏技术的宝贵材料。它包括两篇精心编写的PDF文档:一篇深入剖析了木马如何利用各种技术隐藏自己,包括基于...在使用这些资源时,请确保遵守相关法律法规,切勿用于非法目的。
最新支付宝暗视频打赏源码带搭建教程切勿运营