关于swing:java中的双{{}}语法问题

Double {{ }} syntax question in java

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicates:
Efficiency of Java “Double Brace Initialization”?
Meaning of new Class(…){{…}} initialization idiom

假设我创建了一个jmenu栏,方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<wyn>
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);
    }};
</wyn>

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


您所做的操作称为"初始化块"。

来自DOC:

The Java compiler copies initializer
blocks into every constructor.
Therefore, this approach can be used
to share a block of code between
multiple constructors

例子:

1
2
3
4
5
6
7
8
9
class A {
    private String field1;

    {
        field1 ="example field";
        field2 = getstaticResult();
    }

}

但在我看来,我们不应该经常使用它,尤其是在您的情况下,使用它是非常不寻常的。


双括号初始化实际上没有什么问题;我经常将它用于映射和列表。

这可能取决于你的听众是谁——你团队中的其他人明白你在这里做什么吗?记住,总有一天,会有人读到这段代码。


你好像在问(至少)两个不同的问题。双括号习惯用法是已知的,常用作创建匿名内部类的简写,将显式构造函数替换为初始值设定项块。通常这会使代码更具可读性,所以我认为这是可以的。

由于(非静态)初始值设定项块是语言的一个相对较新的添加,因此一些开发人员可能不熟悉它们,这可能会造成混淆。当然,和几乎所有的技术一样,当过度使用时,它会产生比它解决的问题更多的问题。


两个问题

  • 泄漏引用:由于这些是匿名的内部类,所以它们保留对周围对象的引用,从而防止收集它们。这可能导致难以找到内存泄漏。

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

如果您知道上面的内容不会有问题,那么使用这种语法没有任何问题。


像大多数这种性质的问题一样,不幸的是,我必须说"视情况而定"。当你这样做的时候,你实际上是在创建一个新的匿名类,所以在内存和CPU方面有一个非常小的性能冲击,但是在大多数情况下,我会说这是微不足道的,足以忽略。如果这样做可以使代码更具可读性,并且是团队其他成员使用的样式,那么我建议您使用它。