6

我偶然发现了这个从匿名内部类获取值到在外部类中声明的变量的技巧。它有效,但感觉就像一个肮脏的黑客:

private int showDialog()
{
    final int[] myValue = new int[1];

    JPanel panel = new JPanel();
    final JDialog dialog = new JDialog(mainWindow, "Hit the button", true);
    dialog.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );

    JButton button = new JButton("Hit me!");
    button.addActionListener(new ActionListener()
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            myValue[0] = 42;
            dialog.setVisible(false);
        }
    });

    panel.add(button);
    dialog.add(panel);
    dialog.pack();
    dialog.setVisible(true);

    return myValue[0];
}

(是的,我意识到这个例子可以用 simple 代替JOptionPane,但我的实际对话框要复杂得多。)内部函数坚持认为它与之交互的所有变量都是final,但我不能将其声明myValue为 final,因为内部函数需要为其分配一个值。将其声明为 1 元素数组可以解决此问题,但似乎它可能是一个 Bad Thing TM。我想知道a.)这是常见的做法还是b.)这样做可能会导致任何严重的问题。

4

4 回答 4

3

如果代码清晰易读,我不会说这样做很糟糕。

另一种方法是让 JButton 调用具有 showDialog 的类中的函数(这是允许的)。该函数可以设置将返回的实例变量。但这对我来说似乎不太清晰,所以我实际上更喜欢你的方法。

除非您正在制作一个层次分明的 UI 框架,否则有时这些小技巧正是您应该做的事情。

如果您担心,您可以对私有内部类执行基本相同的操作:

private class DialogReturnValue {
    public int value;
}

private int showDialog()
{
    final DialogReturnValue myValue = new DialogReturnValue();

    JPanel panel = new JPanel();
    final JDialog dialog = new JDialog(mainWindow, "Hit the button", true);
    dialog.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );

    JButton button = new JButton("Hit me!");
    button.addActionListener(new ActionListener()
    {
        @Override
        public void actionPerformed(ActionEvent e)
        {
            myValue.value = 42;
            dialog.setVisible(false);
        }
    });

    panel.add(button);
    dialog.add(panel);
    dialog.pack();
    dialog.setVisible(true);

    return myValue.value;
}

还有 ActionListeners 可供查看(这很可能是“正确”的方法)。

于 2013-10-24T00:09:40.577 回答
1

使用 AtomicInteger 或 AtomicReference 可以让它变得更好。这实际上是一种常见的做法,但是您可以通过引入实现 ActionListener 并通过 getter 提供值的实际类来使其更简洁。

于 2013-10-24T00:11:44.400 回答
0

那看起来确实很脏。我真的不能说它有多“普遍”,我不知道你这样做是在冒着毁灭世界的风险,但如果我需要这样的东西,我宁愿硬着头皮写一个成熟的内部类(而不是匿名种类)来实现ActionListener. 这样,您可以让它影响其封闭类的字段并根据需要调用封闭类中的其他方法。取决于你到底在做什么,甚至可能值得全力以赴并继承Dialog这个逻辑。

作为奖励,非匿名内部类使调试变得不那么痛苦,因为您可以获得更多信息类标识符。

于 2013-10-24T00:07:59.107 回答
0

我认为您的代码没有问题。有时我不得不求助于类似的东西,但我使用了一个包装值的特殊类,我在内部类中调用了一个 setter,但最终结果是相同的。

private static class Result{
   private Integer value;

   //getter and setters here

}

....

final Result result = new Result();

...
new InnerClass(){

   void foo(){
       result.setValue(42);
   }
}

问题是内部类只能引用最终变量,因为它们的内存地址不会改变。

我对您的唯一建议是不要使用 anint[]作为值,而是使用 anInteger[]这样您就可以区分值 0 和未设置的值(其值 = null)。

于 2013-10-24T00:07:59.140 回答