web-dev-qa-db-ja.com

パラメータを匿名クラスに渡す方法は?

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

int myVariable = 1;

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

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

142
Lewis

技術的には、匿名クラスにはコンストラクターがないためです。

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

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

76
Matthew Willis

はい、「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)  );

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

328
Adam Mlodzinski

はい。内部クラスから見える変数をキャプチャできます。唯一の制限は、finalでなければならないことです

27
aav

このような:

final int myVariable = 1;

myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // Now you can access it alright.
    }
});
20
adarshr

これは魔法を行います

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));
13
user3510955

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

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

8
Rob Russell

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

例:(テキストボックスの変更を処理する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);
7

他の人々はすでに、匿名クラスはfinal変数のみにアクセスできると答えています。しかし、元の変数を非ファイナルに保つ方法についての質問は未解決のままです。 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は彼の答えでは他に何もしませんが、より多くのコードを使用します。

3
ceving

plain lambdas (「ラムダ式は変数をキャプチャできる」)を使用できます

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) );

関数の使用は、デコレータとアダプタをリファクタリングするのに最適な方法です こちらを参照

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

3
ZiglioUK

外部変数に値を入力する簡単な方法(anonymusクラスに属さない)は、どれだけ小さいかです!

同じ方法で、外部変数の値を取得したい場合、必要なものを返すメソッドを作成できます!

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

    });

 }
1
heronsanches