Включены ли экземпляры перечисления в тип перечисления в java?

Репродуктор:

enum IDs {
    ID {

        @Override
        void getId() {
            w(); // warning here
        }
    };

    void getId() {}

    private static void w() {}
}

Выдано предупреждение:

Доступ к включающему методу w () из идентификаторов типов эмулируется синтетическим методом доступа.

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


person Mr_and_Mrs_D    schedule 19.10.2013    source источник


Ответы (1)


Экземпляр перечисления, который определяет методы, как здесь ваш ID, является синглтоном неявного анонимного подкласса класса перечисления. Между подклассом и классом enum применяются обычные правила доступа, поэтому для просмотра частных функций класса enum требуется синтетический метод доступа.

Спецификация языка Java требует, чтобы перечисления работать так:

Необязательное тело класса константы перечисления неявно определяет объявление анонимного класса (§15.9.5), которое расширяет непосредственно включающий тип перечисления. Тело класса регулируется обычными правилами анонимных классов ...

Конечно, так они реализованы на самом деле. В javac JDK это происходит в _ 2_ вокруг строки 3344 (в этой версии):

JCClassDecl body = null;
if (token.kind == LBRACE) {
    JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC);
    List<JCTree> defs = classOrInterfaceBody(names.empty, false);
    body = toP(F.at(identPos).AnonymousClassDef(mods1, defs));
}
if (args.isEmpty() && body == null)
    createPos = identPos;
JCIdent ident = F.at(identPos).Ident(enumName);
JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body);

Соответствующие биты заключаются в том, что если в объявлении есть левая фигурная скобка (LBRACE), тогда тело класса анализируется (classOrInterfaceBody(...)) для анонимного класса (names.empty), а затем оно используется в качестве тела класса при создании экземпляра. выражение (NewClass(..., body)). Вы можете выполнить компиляцию JCNewClass узлов, если хотите, но достаточно сказать, как это делает его javadoc, что он моделирует:

 * A new(...) operation.

Как вы знаете, new операция с телом класса создает анонимный класс.

person Tom Anderson    schedule 19.10.2013