Доступ к конструктору анонимного класса

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

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

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

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

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

12.12.2008 10:34:23
Стоит прочитать DoubleBraceInitialization
Ken Kin 27.10.2014 02:17:25
В случае, если у родителя есть конструктор: stackoverflow.com/questions/20807148/…
Vadzim 7.05.2018 15:11:56
10 ОТВЕТОВ
РЕШЕНИЕ

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

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

278
15.12.2016 22:33:39
Арне, я верю ему, что он не копировал это. он знает достаточно о java, чтобы быть достаточно справедливым, чтобы отдать должное, когда он скопировал бы его, я думаю.
Johannes Schaub - litb 12.12.2008 16:42:06
О, Боже, кто-то обвинил Джона Скита в копировании?
user 15.08.2012 17:43:40
Как я смогу вызвать метод в суперклассе Test из println, если этот метод переопределен?
Mark Jeronimus 25.02.2014 14:56:14
@ Zom-B: Не совсем понятно, что вы имеете в виду - я подозреваю, что стоит задать новый вопрос с примером того, чего вы пытаетесь достичь.
Jon Skeet 25.02.2014 15:01:33
ах, я хотел переопределить конструктор суперкласса ... тогда я понял, что no explicitly declaredctor тоже не означает переопределения. Я предполагаю.
n611x007 19.03.2014 15:55:25

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

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

  void someNewMethod() {
  }
};

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

98
12.12.2008 10:53:05

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

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

1
12.12.2008 13:34:39
При желании язык может легко превратить «нормальные» аргументы конструктора в аргументы для анонимного класса. Синтаксис для объявления конструктора, вероятно, выглядел бы довольно странно, хотя ...
Jon Skeet 12.12.2008 17:19:26
нельзя было просто сказать объявить конструктор, как если бы это был конструктор базового класса? Я не вижу проблем с этим
Johannes Schaub - litb 28.12.2008 06:48:54

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

2
8.07.2009 18:45:48

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

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();
    }
}
75
26.09.2018 07:09:58
Хорошее решение, но использование Thread здесь поначалу вводит его в заблуждение (на мгновение я подумал, что вы создали отдельный поток для инициализации
scorpiodawg 10.05.2012 17:47:50
Обратите внимание, что после tопределения вы не можете вызывать, t.initialise()если эта функция не определена в классе / типе интерфейса.
Aram Kocharyan 6.03.2013 12:29:30
@AramKocharyan Это делает его еще более похожим на конструктор.
v010dya 11.10.2015 09:07:10
Я люблю это решение! Это делает очевидным, что initialise()метод вызывается после конструктора Thread. С другой стороны, было (по крайней мере, мне) не очевидно, что с инициализатором экземпляра это всегда гарантировано.
muelleth 20.12.2016 13:28:22

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

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
7.12.2012 00:20:10

Если вам не нужно передавать аргументы, тогда достаточно кода инициализатора, но если вам нужно передать аргументы от разработчика, есть способ решить большинство случаев:

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
28.07.2012 01:24:31
Если я понимаю, ваш код anonymousClass должен наследовать от String (setVar является типом String и возвращает его), но String не является расширяемым. Я полагаю, setVar должен возвращать то, что расширяет anonymousClass.
alfoks 2.12.2016 09:23:23

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

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

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

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

3
31.01.2013 12:42:14

Питер Норвиг из 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
13.11.2014 15:31:47
Я не знал Питера Норвига, ученого из Google, это, вероятно, одна из его ранних работ, это о Java 1.1! Интересно с исторической точки зрения :)
pdem 15.02.2017 17:04:52

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

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

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

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

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

13
22.09.2015 11:35:58