Почему в этой ситуации генерируется класс $ 1.class?

Я написал следующий код для реализации шаблона Singleton:

public final class Test {
     static final class TestHolder {
         private static final Test INSTANCE = new Test();
     }     

     private Test() {}

     public static Test getInstance() {
         return TestHolder.INSTANCE;
     }
}

Когда я компилирую этот файл, он должен генерировать Test.class и Test $ TestHolder.class, но также генерирует Test $ 1.class. Это не имеет смысла. Так почему и как это будет?

Ответ 1

Класс TestHolder должен вызвать частный конструктор в Test. Но он частный, и на самом деле его нельзя называть из другого класса. Итак, компилятор играет в трюк. Он добавляет новый не-частный конструктор для Test который только он знает! Этот конструктор принимает (неиспользуемый) экземпляр этого анонимного класса Test$1 - который никто не знает. Затем TestHolder создает экземпляр Test$1 и вызывает этот конструктор, который доступен (по умолчанию он защищен).

Вы можете использовать javap -c Testjavap -c Test\$1 и javap -c Test\$TestHolder), чтобы увидеть код. Это довольно умный, на самом деле!