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

(はい、この例を単純な に置き換えることができることは理解してJOptionPaneいますが、実際のダイアログはもっと複雑です。) 内部関数は、相互作用するすべての変数が であると主張していますが、内部関数が必要とするため、 を final としてfinal宣言することはできません。myValue値を割り当てます。これを 1 要素の配列として宣言すると、この問題は回避されますが、何らかの形で Bad Thing TMになる可能性があるようです。a.) これが一般的な慣行なのか、b.) これを行うことで深刻な問題が発生するのか、疑問に思っています。

4

4 に答える 4

3

コードが判読可能であれば、そのようにすることがひどいとは言えません。

別の方法として、showDialog を持つクラスの関数を JButton に呼び出させることもできます (これは許可されています)。この関数は、返されるインスタンス変数を設定できます。しかし、それは私には読みにくいように思われるので、実際にはあなたの方法を好むでしょう.

深く階層化された 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

あなたのコードに問題があるとは思いません。私は時々似たようなことに頼らなければなりませんが、値をラップする特別なクラスを使用し、内部クラスでセッターを呼び出しますが、最終結果は同じです。

private static class Result{
   private Integer value;

   //getter and setters here

}

....

final Result result = new Result();

...
new InnerClass(){

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

問題は、メモリアドレスが変更されないため、内部クラスが最終変数のみを参照できることです。

唯一のアドバイスはint[]、値としてan を使用するのではなく、an を使用するInteger[]ことです。これにより、値 0 と設定されていない値 (値 = null になります) の違いがわかります。

于 2013-10-24T00:07:59.140 に答える