java中的双{{}}语法问题

可能重复:
Java“双支撑初始化”的效率?
new Class(…){{…}}初始化习语的含义

假设我通过以下方式创建了一个JMenu Bar:

JMenuItem saveMenuItem = new JMenuItem("Save") {{ addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String location = GUI.Custom.QuickDialogs.selectFile(false); try { PrintWriter pw = new PrintWriter(new File(location)); String text = textArea.getText(); pw.println(text); pw.flush(); pw.close(); } catch(Exception ex) { textArea.append("Could not save this debug output"); } } }); }}; JMenu optionsMenu = new JMenu("Options") {{ add(saveMenuItem); setVisible(true); }}; private JMenuBar menuBar = new JMenuBar() {{ add(optionsMenu); setVisible(true); }}; 

这是一种糟糕的设计模式,以这种方式创建对象,而不是仅仅声明变量,然后在构造函数或其他东西中创建?

你所做的是:“初始化块”。

来自doc:

Java编译器将初始化程序块复制到每个构造函数中。 因此,该方法可用于在多个构造函数之间共享代码块

例:

 class A { private String field1; { field1 = "example field"; field2 = getstaticResult(); } } 

但在我看来,我们不应该经常使用它,特别是在你的情况下使用它是非常不寻常的。

双支撑初始化没有任何问题 ; 我经常将它用于地图和列表。

这可能取决于您的观众是谁 – 您团队中的其他人是否了解您在这里做了什么? 请记住,有一天,某人将不得不阅读此代码。

你似乎在这里问(至少)两件不同的事情。 双括号习语是已知的,通常用作创建匿名内部类的简写,用初始化块替换显式构造函数。 通常这会使代码更具可读性,所以我会说它没问题。

OTOH因为(非静态)初始化块是该语言的一个相对较新的补充,但是一些开发人员可能不熟悉它们,这可能会造成混淆。 当然,与几乎所有技术一样,当过度使用时,它会产生比它解决的更多问题。

像大多数这种性质的问题一样,不幸的是我必须说“这取决于”。 当你这样做的时候,你实际上是在创建一个新的匿名类,所以在内存和CPU方面有一个非常轻微的性能损失,但在大多数情况下,我会说这是无足轻重的。 如果以这种方式这样做会使你的代码更具可读性,如果它是团队其他成员正在使用的风格,我会说要配合它。

两个问题

  • 泄漏引用:由于这些是匿名内部类,因此它们保留对周围对象的引用,这将使它们不被收集。 这可能导致很难找到内存泄漏。

  • 匿名类型:对于任何依赖于确切类的东西,这可能会导致问题。 例如,序列化和equals的某些实现可能无法按预期工作。

如果您知道上述问题不会成为问题,那么使用此语法并没有错。