Есть ли способ инициализировать финальное поле в классе анонимуса?

В Java мы можем инициализировать поле final в конструкторах как в базовом классе, так и в его подклассах, а также во встроенном блоке инициализатора в базовом классе. Однако кажется, что мы не можем инициализировать поля final во встроенном блоке инициализатора в подклассе. Это поведение в основном затрагивает анонимные классы, из которых нельзя вызывать конструкторы super.

abstract class MyTest {

    final protected int field;

    public MyTest() {
        // default value
        field = 0;
    }

}

MyTest anonymTest = new MyTest() {
    {
        // Error: The final field MyTest.field cannot be assigned
        field = 3;
    }
};

Есть ли способ инициализировать унаследованное поле final в классе анонимуса?

Комментарий. Этот вопрос касается не конструкторов, а окончательной инициализации поля.


person Dávid Horváth    schedule 04.04.2016    source источник
comment
Речь идет не о конструкторах, а об окончательной инициализации полей.   -  person Dávid Horváth    schedule 04.04.2016
comment
Верно, но единственная ситуация, в которой вы можете установить поле final из подкласса, — это через суперконструктор. Так что этот дубликат охватывает единственную допустимую ситуацию для вашего вопроса.   -  person resueman    schedule 04.04.2016
comment
Я не согласен. Если нет другого пути, кроме конструктора, то это и есть ответ на вопрос.   -  person Dávid Horváth    schedule 04.04.2016
comment
Если нет другого способа, кроме конструктора, то это ответ на вопрос. ... мой вопрос будет таким: почему вы хотите иметь возможность создавать экземпляры, используя механизм, отличный от этого тот, который был предназначен, т.е. конструкторы? Предполагается, что конструктор — это единственное место, где объекты инициализируются и проверяются. Обходить этот механизм кажется неразумным.   -  person scottb    schedule 04.04.2016
comment
@scottb: На самом деле причин несколько. Например, new Foo(){{a=1;b=2;}} является более явным/понятным, чем new Foo(1,2){}. На самом деле исходная проблема заключается в том, что абстрактные классы не допускают неинициализированные поля final. См.: stackoverflow.com/questions/2327509/   -  person Dávid Horváth    schedule 04.04.2016
comment
@DávidHorváth: Я не думаю, что вы когда-нибудь заставите меня согласиться с тем, что new Foo() {{a=1; b=2;}} более читабелен или понятен, чем new Foo(1,2);. Для более сложных случаев, связанных с инициализацией неизменяемых классов, Builders также очень просты для чтения и понимания, и они облегчают использование необязательных параметров.   -  person scottb    schedule 05.04.2016
comment
В общем, я согласен. Вызов конструктора — это стандартный и безопасный способ инициализации полей, а Builder — отличное решение для сложных ситуаций. Однако в некоторых простых случаях было бы полезно, просто и элегантно, если бы мы могли явно задавать поля, независимо от того, окончательные они или нет. Это не такой C-иш, как кажется на первый взгляд.   -  person Dávid Horváth    schedule 05.04.2016


Ответы (2)


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

abstract class MyTest {

    final protected int field;

    public MyTest() {
        // default value
        this(0);
    }

    public MyTest(int f) {
        field = f;
    }

}


MyTest anonymTest = new MyTest(3) {
};

Обновление: добавлен конструктор для использования значения по умолчанию.

person gustf    schedule 04.04.2016

Конечные переменные экземпляра должны быть инициализированы в конструкторе.

abstract class MyTest {

final protected int field;

public MyTest() {
    // default value
    field = 0;
}

public MyTest(int val)
{
   // will set the final field to the specified val
   field = val;
}

}
person KevinO    schedule 04.04.2016