153

パラメータを渡したり、匿名クラスに外部パラメータにアクセスしたりすることは可能ですか?例えば:

int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // How would one access myVariable here?
    }
});

リスナーを実際の名前付きクラスとして作成せずに、リスナーがmyVariableにアクセスしたり、myVariableを渡したりする方法はありますか?

4

12 に答える 12

352

はい、「this」を返す初期化メソッドを追加し、すぐにそのメソッドを呼び出します。

int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    private int anonVar;
    public void actionPerformed(ActionEvent e) {
        // How would one access myVariable here?
        // It's now here:
        System.out.println("Initialized with value: " + anonVar);
    }
    private ActionListener init(int var){
        anonVar = var;
        return this;
    }
}.init(myVariable)  );

「最終」宣言は必要ありません。

于 2012-08-30T22:34:34.563 に答える
81

技術的には、いいえ。匿名クラスはコンストラクターを持つことができないためです。

ただし、クラスはスコープを含む変数を参照できます。匿名クラスの場合、これらは、包含クラスのインスタンス変数、またはfinalとマークされたローカル変数にすることができます。

編集:Peterが指摘したように、匿名クラスのスーパークラスのコンストラクターにパラメーターを渡すこともできます。

于 2011-02-24T16:08:22.947 に答える
31

はい。内部クラスに表示される変数をキャプチャできます。唯一の制限は、それが最終的でなければならないということです

于 2011-02-24T16:05:44.807 に答える
22

このような:

final int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // Now you can access it alright.
    }
});
于 2011-02-24T16:06:26.823 に答える
14

これは魔法を行います

int myVariable = 1;

myButton.addActionListener(new ActionListener() {

    int myVariable;

    public void actionPerformed(ActionEvent e) {
        // myVariable ...
    }

    public ActionListener setParams(int myVariable) {

        this.myVariable = myVariable;

        return this;
    }
}.setParams(myVariable));
于 2014-12-18T13:46:01.030 に答える
8

http://www.coderanch.com/t/567294/java/java/declare-constructor-anonymous-classに示されているように、インスタンス初期化子を追加できます。これは名前がなく、最初に実行されるブロックです(コンストラクターのように)。

なぜJavaインスタンス初期化子についても説明されているようです。インスタンス初期化子はコンストラクターとどのように異なりますか?コンストラクターとの違いについて説明します。

于 2013-02-18T01:00:18.807 に答える
7

私の解決策は、実装された匿名クラスを返すメソッドを使用することです。通常の引数をメソッドに渡すことができ、匿名クラス内で使用できます。

例:(テキストボックスの変更を処理するための一部のGWTコードから):

/* Regular method. Returns the required interface/abstract/class
   Arguments are defined as final */
private ChangeHandler newNameChangeHandler(final String axisId, final Logger logger) {

    // Return a new anonymous class
    return new ChangeHandler() {
        public void onChange(ChangeEvent event) {
            // Access method scope variables           
            logger.fine(axisId)
        }
     };
}

この例では、新しい匿名クラスメソッドは次のように参照されます。

textBox.addChangeHandler(newNameChangeHandler(myAxisName, myLogger))

または、OPの要件を使用します。

private ActionListener newActionListener(final int aVariable) {
    return new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("Your variable is: " + aVariable);
        }
    };
}
...
int myVariable = 1;
newActionListener(myVariable);
于 2013-04-18T09:11:05.410 に答える
3

他の人々は、匿名クラスは最終変数にしかアクセスできないとすでに答えています。しかし、彼らは元の変数を非最終的に保つ方法についての質問を開いたままにします。Adam Mlodzinskiが解決策を示しましたが、かなり肥大化しています。この問題には、はるかに簡単な解決策があります。

ファイナルになりたくない場合myVariableは、ファイナルであれば問題にならない新しいスコープでラップする必要があります。

int myVariable = 1;

{
    final int anonVar = myVariable;

    myButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            // How would one access myVariable here?
            // Use anonVar instead of myVariable
        }
    });
}

Adam Mlodzinskiは、彼の答えでは他に何もしていませんが、はるかに多くのコードを使用しています。

于 2013-10-30T16:40:48.090 に答える
3

プレーンラムダを使用できます(「ラムダ式は変数をキャプチャできます」)

int myVariable = 1;
ActionListener al = ae->System.out.println(myVariable);
myButton.addActionListener( al );

または関数ですら

Function<Integer,ActionListener> printInt = 
    intvar -> ae -> System.out.println(intvar);

int myVariable = 1;
myButton.addActionListener( printInt.apply(myVariable) );

関数の使用は、デコレータとアダプタをリファクタリングするための優れた方法です。ここを参照してください

ラムダについて学び始めたばかりなので、間違いを見つけたら、遠慮なくコメントを書いてください。

于 2017-03-14T21:46:25.897 に答える
1

外部変数(匿名クラスに属していない)に値を入れる簡単な方法は、次のとおりです。

同様に、外部変数の値を取得したい場合は、必要なものを返すメソッドを作成できます。

public class Example{

    private TypeParameter parameter;

    private void setMethod(TypeParameter parameter){

        this.parameter = parameter;

    }

    //...
    //into the anonymus class
    new AnonymusClass(){

        final TypeParameter parameterFinal = something;
        //you can call setMethod(TypeParameter parameter) here and pass the
        //parameterFinal
        setMethod(parameterFinal); 

        //now the variable out the class anonymus has the value of
        //of parameterFinal

    });

 }
于 2014-07-03T22:41:07.530 に答える
1

「myVariable」がフィールドの場合、修飾されたこれを使用できます。

public class Foo {
    int myVariable = 1;

    new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            Foo.this.myVariable = 8;
        }
    });
}
于 2022-01-02T19:33:26.420 に答える
-2

匿名クラスは基本的にラムダのようなものだと思いましたが、構文が悪いです...これは本当ですが、構文はさらに悪く、ローカル変数が含まれているクラスにブリードアウトします。

親クラスのフィールドにすることで、final変数にアクセスできません。

例えば

インターフェース:

public interface TextProcessor
{
    public String Process(String text);
}

クラス:

private String _key;

public String toJson()
{
    TextProcessor textProcessor = new TextProcessor() {
        @Override
        public String Process(String text)
        {
            return _key + ":" + text;
        }
    };

    JSONTypeProcessor typeProcessor = new JSONTypeProcessor(textProcessor);

    foreach(String key : keys)
    {
        _key = key;

        typeProcessor.doStuffThatUsesLambda();
    }

彼らがこれをjava8で整理したかどうかはわかりませんが(私はEEの世界で立ち往生していて、まだ8を取得していません)、C#では次のようになります。

    public string ToJson()
    {
        string key = null;
        var typeProcessor = new JSONTypeProcessor(text => key + ":" + text);

        foreach (var theKey in keys)
        {
            key = theKey;

            typeProcessor.doStuffThatUsesLambda();
        }
    }

C#でも個別のインターフェイスは必要ありません...私はそれが恋しいです!何かを再利用するためにJavaに追加しなければならないコードの量と複雑さは、多くの時間をコピーして貼り付けるよりも悪いため、Javaでより悪いデザインを作成し、繰り返します。

于 2014-09-09T14:06:31.583 に答える