为匿名内部类使用最终的1元素数组

时间:2013-10-23 23:59:14

标签: java swing dialog anonymous-function final

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

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];
}

(是的,我知道这个例子可以用简单的JOptionPane替换,但我的实际对话框要复杂得多。)内部函数坚持认为它与之交互的所有变量都是final,但是我无法将myValue声明为final,因为内部函数需要为其赋值。将它声明为1元素阵列解决了这个问题,但似乎它可能是某种坏事 TM 。我想知道是否a。)这是常见做法或b。)这可能导致任何严重问题。

4 个答案:

答案 0 :(得分: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可供查看(这可能是“正确的”方法)。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

看起来很脏。我真的不能说它是多么“普通”,而且我不知道你这样做会冒着破坏世界的风险,但如果我需要这样的东西,我宁愿咬紧牙关写一个完整的内部类(而不是匿名变种)来实现ActionListener。这样你可以让它影响它的封闭类的字段,并根据需要调用封闭类中的其他方法。根据你正在做的事情,甚至可能值得全押和继承Dialog以保持这种逻辑。

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

答案 3 :(得分: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);
   }
}

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

我唯一的建议是不要使用int[]作为值而是使用Integer[],这样就可以区分值0和未设置的值(这将具有value = null)。