порядок загрузчика классов в Java во время компиляции и выполнения - PullRequest
0 голосов
/ 30 июня 2018

Я создал класс ниже с квалифицированным именем java.lang.String в Java.

package java.lang;

public class String {
    public int getValue() {
        return 42;
   }
}

В основной класс я добавил следующий код.

public class Main {

    public static void main(String[] args) {
        String s = new String();
        System.out.println(s.getValue());
    }
}

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

 Exception in thread "main" java.lang.NoSuchMethodError:    java.lang.String.getValue()I
at com.Main.main(Main.java:12)

Я понял, что java.lang.String загружается загрузчиком классов начальной загрузки во время выполнения из файла rt.jar.

Итак, я думаю, что порядок загрузки классов должен отличаться во время компиляции и выполнения. Можете ли вы дать порядок загрузки классов во время компиляции и во время выполнения.

1 Ответ

0 голосов
/ 30 июня 2018

Прежде всего, этот тест не будет работать в Java 9 или новее. Попытка скомпилировать класс String приведет к этой ошибке:

java/lang/String.java:1: error: package exists in another module: java.base
package java.lang;
^

На Java 8 я получаю поведение, которое вы видите. Предполагая, что измененный класс String находится в том же дереве исходного кода, класс Main компилируется, но выдает исключение при попытке его запустить.

Это, как представляется, сообщается как ошибка 4929425 . Решением было то, что это была ошибка документации, и они уточнили документацию для команды javac ... хотя, возможно, этого недостаточно.

Во всяком случае, есть разница, и она тонкая.

Команда java просто ищет в следующем порядке:

  • путь начальной загрузки
  • каталоги расширений
  • 1024 * Путь к классам *

Команда javac сначала ищет исходный каталог. Если он находит там исходный файл, он ищет соответствующий файл класса в том же месте и (при необходимости) компилирует или перекомпилирует его. Если исходный файл не найден, он ищет пути к классам для файла класса, как описано выше для java.

Обратите внимание, что требуется очень осторожное чтение ручной записи javac, чтобы выявить это. Это легко пропустить. (https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html#searching)

(IMO, они могут сделать страницу руководства более понятной. Однако это несоответствие имеет значение только в том случае, если вы пытаетесь переопределить какой-либо класс в пути начальной загрузки или в каталоге расширений. И вы делаете это неправильно. В основном Это крайний случай. Проблема с четким документированием непонятных крайних случаев заключается в том, что вы можете сделать документацию более запутанной для обычного случая.)

...