Как используется поле INNERCLASS в классах Java?

Я посмотрел на некоторый Java-байт-код, используя ASM, и был очень удивлен, увидев эти строки

public class C1 {

  // compiled from: C1.java
  // access flags 0x9
  public static INNERCLASS C2$C3 C2 C3

  //..
}

C1 имеет INNERCLASS объявление для класса, содержащегося в C2, Это так и должно быть? Если да, то зачем это нужно, и не приводит ли это к большой избыточности?

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


public class C1 {
    public static void main(String[] args) throws Exception {
        C2.C3 c3 = new C2.C3();

        ClassReader cr = new ClassReader(C1.class.getName());
        cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), 0);
    }
}

public class C2 {
    public static class C3 {}
}

1 ответ

Решение

Из спецификации виртуальной машины Java:

Если пул констант класса или интерфейса C содержит хотя бы одну запись CONSTANT_Class_info (§4.4.1), которая представляет класс или интерфейс, который не является членом пакета, то в таблице атрибутов должен быть ровно один атрибут InnerClasses структура ClassFile для C.

Это InnerClasses Атрибут ссылается на все внутренние классы ("класс или интерфейс не является членом пакета"), на которые есть ссылки в файле класса, даже если они не являются членами класса, содержащегося в файле класса. Еще один случай (который можно назвать внешними классами из- за отсутствия конкретного термина) явно упоминается в примечании:

Кроме того, таблица constant_pool каждого вложенного класса и вложенного интерфейса должна ссылаться на свой включающий класс, поэтому в целом каждый вложенный класс и вложенный интерфейс будут иметь информацию InnerClasses для каждого вложенного класса и для каждого из своих собственных вложенных классов и интерфейсов.

Относительно того, почему эти внешние ссылки необходимы, я не совсем уверен, за исключением того, что хочу отметить, что внутренние классы были добавлены в Java 1.1 после того, как формат файла класса был в основном заморожен, поэтому информация о внутренних классах не сохраняется непосредственно в ClassFile структура (структура верхнего уровня файла класса), как суперкласс, интерфейсы, поля и методы. Также обратите внимание, что InnerClasses Атрибут составляет 8 байтов плюс 8 байтов для каждого внутреннего класса, на который ссылаются - это вряд ли чрезмерная степень избыточности.

Другие вопросы по тегам