web-dev-qa-db-ja.com

匿名クラスのコンストラクターにアクセスする

具体的なクラスClass1があり、そこから匿名クラスを作成しているとしましょう。

Object a = new Class1(){
        void someNewMethod(){
        }
      };

これで、この匿名クラスのコンストラクタをオーバーロードできる方法があります。以下のように

Object a = new Class1(){
        void someNewMethod(){
        }
        public XXXXXXXX(int a){
          super();
          System.out.println(a);
        }
      };

Xxxxxxxxに何か名前を付けてコンストラクタを指定しますか?

208
Saravanan M

Java言語仕様 のセクション15.9.5.1から:

匿名クラスは、明示的に宣言されたコンストラクタを持つことはできません。

ごめんなさい :(

編集:別の方法として、いくつかの最終的なローカル変数を作成したり、匿名クラスにインスタンス初期化子を含めることができます。例えば:

public class Test {
    public static void main(String[] args) throws Exception {
        final int fakeConstructorArg = 10;

        Object a = new Object() {
            {
                System.out.println("arg = " + fakeConstructorArg);
            }
        };
    }
}

むちゃくちゃですが、あなたを助けるかもしれません。または、適切なネストされたクラスを使用します:)

269
Jon Skeet

それは不可能ですが、次のような匿名の初期化子を追加できます。

final int anInt = ...;
Object a = new Class1()
{
  {
    System.out.println(anInt);
  }

  void someNewMethod() {
  }
};

AnIntで行ったように、匿名クラスで使用されるローカル変数またはパラメーターの宣言のfinalを忘れないでください。

96
Arne Burmeister

問題を回避する別の方法を次に示します。

public class Test{

    public static final void main(String...args){

        new Thread(){

            private String message = null;

            Thread initialise(String message){

                this.message = message;
                return this;
            }

            public void run(){
                System.out.println(message);
            }
        }.initialise(args[0]).start();
    }
}
72
Joel Shemtov

私はスレッドが古すぎて答えを投稿できないことを知っています。しかし、それでも価値があると思います。

明示的なコンストラクターを作成することはできませんが、スーパークラスのコンストラクターを呼び出すことが目的の場合は、次の操作を行うだけです。

StoredProcedure sp = new StoredProcedure(datasource, spName) {
    {// init code if there are any}
};

これは、StoredProcedureおよびDataSourceオブジェクトを渡すことにより、Springで String オブジェクトを作成する例です。

ボトムラインは、匿名クラスを作成してスーパークラスコンストラクターを呼び出したい場合、スーパークラスコンストラクターに一致する署名で匿名クラスを作成します。

Initパラメータを受け入れるコンストラクタを抽象クラスに含めることができます。 Java仕様は、(オプションで)抽象クラスまたはインターフェイスの実装の子孫である匿名クラスが、独自のコンストラクタを持たないことを指定するだけです。

以下は絶対に合法であり、可能です。

static abstract class Q{
    int z;
    Q(int z){ this.z=z;}
    void h(){
        Q me = new Q(1) {
        };
    }
}

抽象クラスを自分で作成する可能性がある場合は、そのようなコンストラクタをそこに配置し、より良い解決策がない場所で流fluentなAPIを使用します。この方法で、元のクラスのコンストラクターをオーバーライドして、パラメーターを持つコンストラクターで名前付きの兄弟クラスを作成し、それを使用して匿名クラスをインスタンス化できます。

3
Peter Verhas

引数を渡す必要がない場合は、初期化コードで十分ですが、contrcutorから引数を渡す必要がある場合は、ほとんどの場合を解決する方法があります。

Boolean var= new anonymousClass(){
    private String myVar; //String for example

    @Overriden public Boolean method(int i){
          //use myVar and i
    }
    public String setVar(String var){myVar=var; return this;} //Returns self instane
}.setVar("Hello").method(3);
2
Whimusical

はい、匿名クラスでコンストラクトを定義できないことは正しいですが、匿名クラスにコンストラクタがないことを意味するものではありません。混乱...実際には、匿名クラスで構成を定義することはできませんが、コンパイラは、呼び出された親コンストラクタと同じシグネチャを持つコンストラクタを生成します。親に複数のコンストラクターがある場合、匿名にはコンストラクターが1つだけあります

2
Akash Shanker

Peter NorvigのJava IAQ:よく聞かれない質問

http://norvig.com/Java-iaq.html#constructors -匿名クラスのコンストラクター

http://norvig.com/Java-iaq.html#init -コンストラクターと初期化

要約すると、このようなものを構築できます。

public class ResultsBuilder {
    Set<Result> errors;
    Set<Result> warnings;

...

    public Results<E> build() {
        return new Results<E>() {
            private Result[] errorsView;
            private Result[] warningsView;
            {
                errorsView = ResultsBuilder.this.getErrors();
                warningsView = ResultsBuilder.this.getWarnings();
            }

            public Result[] getErrors() {
                return errorsView;
            }

            public Result[] getWarnings() {
                return warningsView;
            }
        };
    }

    public Result[] getErrors() {
        return !isEmpty(this.errors) ? errors.toArray(new Result[0]) : null;
    }

    public Result[] getWarnings() {
        return !isEmpty(this.warnings) ? warnings.toArray(new Result[0]) : null;
    }
}
2
Diogo Quintela

私の場合、ローカルクラス(カスタムコンストラクターを使用)は匿名クラスとして機能しました。

Object a = getClass1(x);

public Class1 getClass1(int x) {
  class Class2 implements Class1 {
    void someNewMethod(){
    }
    public Class2(int a){
      super();
      System.out.println(a);
    }
  }
  Class1 c = new Class2(x);
  return c;
}
1
arnaldocan

とにかくそれを呼び出す方法がないので、匿名クラスに名前付きのオーバーロードされたコンストラクタを持つことは意味がありません。

実際にしようとしていることに応じて、クラスの外部で宣言された最終的なローカル変数にアクセスするか、Arneが示すようにインスタンス初期化子を使用するのが最善の解決策です。

1
Ilja Preuß