Почему все анонимные классы неявно окончательные?

Согласно JLS:

15.9.5 Объявления анонимных классов Объявление анонимного класса автоматически выводится компилятором из выражения создания экземпляра класса.

Анонимный класс никогда не бывает абстрактным (§8.1.1.1). Анонимный класс всегда является внутренним классом (§8.1.3); он никогда не бывает статичным (§8.1.1, §8.5.2). Анонимный класс всегда неявно окончательный (§8.1.1.2).

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

Если я выберу такой класс:

SomeType foo = new SomeType() {
    @Override
    void foo() {
        super.foo();
        System.out.println("Hello, world!");
    }
};

Почему мне не разрешено создавать подклассы снова, если я так захочу?

SomeType foo = new SomeType() {
    @Override
    void foo() {
        super.foo();
        System.out.println("Hello, world!");
    }
} {
    @Override
    void foo() {
        System.out.println("Hahaha, no super foo for you!");
    }
};

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


person corsiKa    schedule 21.12.2011    source источник
comment
Вы считаете, что синтаксис не позволяет этого? ;-) Возможно, поэтому они сказали неявно final... просто предположили.   -  person David Z    schedule 21.12.2011
comment
при компиляции они не являются анонимными и не приватными. Тем не менее, они по-прежнему содержат метаданные, и их окончательный вариант гарантирует отсутствие суперстранных случаев (за счет их расширения).   -  person bestsss    schedule 21.12.2011
comment
@ Дэвид, есть и техническая причина   -  person bestsss    schedule 21.12.2011
comment
@ Дэвид, нет, я бы не стал. Кажется, что это было преднамеренным дизайнерским решением, чтобы не допустить этого.   -  person corsiKa    schedule 21.12.2011
comment
@bestsss Тот факт, что они не являются частными, делает еще более веским аргументом в пользу того, чтобы их можно было разделить на подклассы.   -  person corsiKa    schedule 21.12.2011
comment
Частные классы не существуют в байт-коде Java, они являются частными пакетами при компиляции. Частный метод/поля, к которым обращаются эти классы, получают специальные средства доступа, в основном static Foo $accessFieldFoo(OutrerType o). Также внешние классы должны знать свои внутренние классы (метаданные), поэтому, если они расширены, это невозможно.   -  person bestsss    schedule 21.12.2011
comment
Единственный способ создать подкласс анонимного класса - это то, что вы показали в своем примере, и это действительно кажется бесполезным. Языковой дизайн, по крайней мере, так же зависит от того, что вы упускаете, чем то, что вы добавляете. Я не вижу никаких технических причин (т.е. вы могли бы реализовать это, если бы действительно хотели), чтобы не делать этого, кроме того, что это добавляет сложности без каких-либо хороший вариант использования.   -  person Voo    schedule 21.12.2011
comment
Основная причина, по которой такая вещь не должна поддерживаться, заключается в том, что она взорвет вашу голову. Работа с внутренними классами и анонимными классами в Java уже ступает по тонкому льду, где у дизайнеров едва ли есть интеллектуальный контроль (если он действительно есть). Нет смысла добавлять совершенно ненужную функцию, которая может привести к непредвиденным осложнениям.   -  person Hot Licks    schedule 21.12.2011
comment
@Voo Дизайн языка — это, по крайней мере, то, что вы упускаете, чем то, что вы добавляете. -- Да, я думаю, что кто-то вроде Дейкстры сказал это несколько десятилетий назад, и это все еще верно.   -  person Hot Licks    schedule 21.12.2011
comment
Как вы сказали, это был бы единственный способ создать подкласс анонимного внутреннего класса, что делает его довольно бессмысленным. Рассмотрим альтернативу. Куда пошло бы финальное ключевое слово, если бы вам пришлось явно сделать его окончательным?   -  person dspyz    schedule 21.12.2011
comment
@dspyz предположительно `new final SomeType() { } { };   -  person corsiKa    schedule 21.12.2011


Ответы (1)


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

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

person Luis Casillas    schedule 21.12.2011
comment
Есть случаи, особенно при тестировании кода (насмешка, шпионаж), где было бы полезно создать подкласс анонимного класса. - person steventrouble; 20.09.2016
comment
Вы не можете создать подкласс класса, к которому в любом случае нельзя обращаться по имени, независимо от того, является ли он окончательным или нет (так же, как вы не можете создать подкласс класса без доступного конструктора). И самая последняя спецификация изменена: "анонимный класс никогда не бывает окончательным" - person Holger; 10.01.2019