Перейти к основному содержимому

IllegalAccessError в Java

· 3 мин. чтения

1. Обзор

В этом кратком руководстве мы обсудим java.lang.IllegalAccessError .

Мы рассмотрим несколько примеров того, когда он выбрасывается и как его избежать.

2. Введение в IllegalAccessError

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

Компилятор отлавливает такие незаконные вызовы, но мы все равно можем столкнуться с ошибкой IllegalAccessError во время выполнения.

Во-первых, давайте рассмотрим иерархию классов IllegalAccessError:

java.lang.Object
|_java.lang.Throwable
|_java.lang.Error
|_java.lang.LinkageError
|_java.lang.IncompatibleClassChangeError
|_java.lang.IllegalAccessError

Его родительский класс — IncompiledClassChangeError. Следовательно, причиной этой ошибки является несовместимое изменение одного или нескольких определений классов в приложении.

Проще говоря, версия класса во время выполнения отличается от той, для которой он был скомпилирован.

3. Как может возникнуть эта ошибка?

Давайте разберемся с этим с помощью простой программы:

public class Class1 {
public void bar() {
System.out.println("SUCCESS");
}
}

public class Class2 {
public void foo() {
Class1 c1 = new Class1();
c1.bar();
}
}

Во время выполнения приведенный выше код вызывает метод bar() в Class1. Все идет нормально.

Теперь давайте изменим модификатор доступа bar() на private и самостоятельно скомпилируем его.

Затем замените предыдущее определение Class1 ( файл .class ) новой скомпилированной версией и перезапустите программу:

java.lang.IllegalAccessError: 
class Class2 tried to access private method Class1.bar()

Приведенное выше исключение говорит само за себя. Метод bar() теперь приватный в Class1. Ясно, что доступ незаконен.

4. IllegalAccessError в действии

4.1. Обновления библиотеки

Рассмотрим приложение, которое использует библиотеку во время компиляции, и она также доступна в пути к классам во время выполнения.

Владелец библиотеки обновляет общедоступный метод до частного, перестраивает его, но забывает обновить другие стороны этого изменения.

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

4.2. Методы интерфейса по умолчанию

Неправильное использование методов по умолчанию в интерфейсах — еще одна причина этой ошибки.

Рассмотрим следующие определения интерфейса и класса:

interface ForEach {
public default void foobar() {
System.out.println("This is a default method.");
}
}

class Super {
private void foobar() {
System.out.println("Super class method foobar");
}
}

Также давайте расширим Super и реализуем ForEach:

class MySubClass extends Super implements ForEach {}

Наконец, давайте вызовем foobar() , создав экземпляр MySubClass:

new MySubClass().foobar();

Метод foobar() является приватным в Super и используется по умолчанию в ForEach. Следовательно , он доступен в иерархии MySubClass.

Поэтому компилятор не ругается, но во время выполнения мы получаем ошибку:

java.lang.IllegalAccessError:
class IllegalAccessErrorExample tried to access private method 'void Super.foobar()'

Во время выполнения объявление метода суперкласса всегда имеет приоритет над методом интерфейса по умолчанию.

Технически foobar от Super должен был называться, но он приватный. Несомненно, будет выброшена ошибка IllegalAccessError .

5. Как этого избежать?

Именно, если мы столкнемся с ошибкой IllegalAccessError , мы должны в первую очередь искать изменения в определениях классов в отношении модификаторов доступа.

Во-вторых, мы должны проверить методы интерфейса по умолчанию, переопределенные модификатором доступа private.

Если сделать метод уровня класса общедоступным, это поможет.

6. Заключение

В заключение, компилятор разрешит большинство незаконных вызовов методов. Если мы все еще сталкиваемся с ошибкой IllegalAccesError , нам нужно изучить изменения определения класса.

Исходный код примеров доступен на GitHub .