Недавно я столкнулся с проблемой получения ошибки времени выполнения java.lang.IllegalAccessError
при попытке доступа из внутреннего класса к защищенному полю, объявленному во внешнем родительском классе, которое было загружено другим загрузчиком классов. Вкратце:
- Класс
Parent
имеет защищенное поле p
. - Класс
Outer
расширяет Parent
. - Класс
Inner
является внутренним класс, определенный в классе Outer
. - Внутри
Inner
класса есть код: Outer.this.p
. - Все классы объявлены в одном пакете.
Обычно он компилируется и работает нормально, пока классы Parent
и Outer
не будут загружены разными загрузчиками классов. В этом случае мы получаем java.lang.IllegalAccessError
при попытке доступа к Outer.this.p
из Inner
. Я нашел старый отчет об ошибке (который, похоже, был функцией), описывающий это поведение:
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6258289
Но разрешение звучит мне противоречиво:
Ключ состоит в том, что в неудачном случае внутренний класс не находится в том же пакете (и не является подклассом) ConcreteCommand / AbstractCommand. Это просто нарушение спецификации Java для защищенных классов.
Звучит правильно. Но если мы объявляем классы Parent
и Outer
в разных пакетах, но загружаем их с помощью одного загрузчика классов (просто создайте образец консольного приложения без каких-либо загрузок jar), мы не получим никаких ошибок. Так что технически это нарушение Java spe c для защищенных классов, но поскольку мы используем внутренний класс, он работает.
Итак, у нас разное поведение для двух случаев «разных пакетов».
- Объявлено в разных пакетах, загружено одним загрузчиком классов - ОК.
- Объявлено в одном пакете, загружено разными загрузчиками классов - НЕ ОК.
Может ли кто-нибудь дать четкое объяснение того, как внутренний класс получает доступ к родительским полям и почему он работает по-разному в двух случаях?