Доступ к конструктору анонимного класса - PullRequest
208 голосов
/ 12 декабря 2008

Допустим, у меня есть конкретный класс Class1 и я создаю из него анонимный класс.

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

Теперь есть ли способ перегрузить конструктор этого анонимного класса. Как показано ниже

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

Что-нибудь в xxxxxxxx, чтобы назвать конструктор?

Ответы [ 10 ]

268 голосов
/ 12 декабря 2008

Из Спецификации языка 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);
            }
        };
    }
}

Это ужасно, но это может просто помочь вам. В качестве альтернативы используйте правильный вложенный класс:)

95 голосов
/ 12 декабря 2008

Это невозможно, но вы можете добавить анонимный инициализатор, например так:

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

  void someNewMethod() {
  }
};

Не забывайте final при объявлении локальных переменных или параметров, используемых анонимным классом, как я это сделал для anInt.

71 голосов
/ 08 января 2010

Вот еще один способ решения проблемы:

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();
    }
}
13 голосов
/ 22 сентября 2015

Я знаю, что ветка слишком старая, чтобы опубликовать ответ. Но все же я думаю, что оно того стоит.

Хотя у вас не может быть явного конструктора, но если вы хотите вызвать конструктор суперкласса, вам нужно сделать следующее:

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

Это пример создания объекта StoredProcedure в Spring путем передачи объекта DataSource и String.

Итак, если вы хотите создать анонимный класс и вызвать конструктор суперкласса, то создайте анонимный класс с сигнатурой , соответствующей конструктору суперкласса .

3 голосов
/ 31 января 2013

Вы можете иметь конструктор в абстрактном классе, который принимает параметры init. Спецификация Java только указывает, что у анонимного класса, который является потомком (необязательно) абстрактного класса или реализации интерфейса, не может быть конструктор по своему собственному праву.

Следующее абсолютно законно и возможно:

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

Если у вас есть возможность написать абстрактный класс самостоятельно, поместите такой конструктор туда и используйте свободный API, где нет лучшего решения. Таким образом, вы можете переопределить конструктор вашего исходного класса, создав именованный родной класс с конструктором с параметрами, и использовать его для создания экземпляра вашего анонимного класса.

2 голосов
/ 13 ноября 2014

Питер Норвиг, 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 голосов
/ 28 июля 2012

Если вам не нужно передавать аргументы, тогда достаточно кода инициализатора, но если вам нужно передать аргументы от 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 голосов
/ 08 июля 2009

Да, это правильно, что вы не можете определить конструкцию в классе Anonymous, но это не значит, что у анонимного класса нет конструктора. Путать ... На самом деле вы не можете определить конструкцию в классе Anonymous, но компилятор генерирует для него конструктор с той же сигнатурой, что и у вызываемого родительского конструктора. Если родитель имеет более одного конструктора, у анонимного будет один и только один конструктор

1 голос
/ 05 мая 2012

В моем случае локальный класс (с пользовательским конструктором) работал как анонимный класс:

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 голос
/ 12 декабря 2008

Нет никакого смысла иметь именованный перегруженный конструктор в анонимном классе, так как в любом случае его нельзя было бы вызвать.

В зависимости от того, что вы на самом деле пытаетесь сделать, лучшим решением может быть просто доступ к конечной локальной переменной, объявленной вне класса, или использование инициализатора экземпляра, как показано Арне.

...