Как Java заставляет классы расширять Object? - PullRequest
3 голосов
/ 07 марта 2019

Как это происходит внутри ? Какой механизм используется? JNI, отражение или что-то другое? Возможно, компилятор включает в себя предложение extends?

Ответы [ 2 ]

0 голосов
/ 08 марта 2019

Это интересный вопрос о внутренностях компилятора Java.Я нашел список документов, обеспечивающих высокий уровень просмотра javac [1] [2] [3] [4] .Исходный код для конкретной реализации, такой как OpenJdk, также можно найти в сети [source] .

Компиляция состоит из 3 шагов высокого уровня [5] :

  1. "разобрать и ввести"
  2. "обработка аннотаций"
  3. "анализировать и генерировать"

Я написал некоторый код для проверки этих шагов, используя API дерева компиляторов, который предоставляет интерфейс для javac.

static class TestFileObject extends SimpleJavaFileObject {
    public TestFileObject() {
        super(URI.create("Test.java"), JavaFileObject.Kind.SOURCE);
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return "class Test { private int x; }";
    }
}

public static void main(String[] args) throws IOException {
    JavacTool tool = JavacTool.create();
    JavacTask task = tool.getTask(null, null, null, null, null,
            com.sun.tools.javac.util.List.of(new TestFileObject()));

    // Step 1, Parse
    Iterator<? extends CompilationUnitTree> trees = task.parse().iterator();

    // Step 3, Analyze
    // Iterator<? extends Element> elements = task.analyze().iterator();

    // Step 3, Generate
    // Iterator<? extends JavaFileObject> files = task.generate().iterator();

    while(trees.hasNext()) {
        CompilationUnitTree cu = trees.next();
        System.out.println(cu.getTypeDecls());
    }
}

Запуск вышеуказанногокод с шагом 1 показывает следующий вывод:

class Test {
    private int x;
}

Таким образом, AST не содержит ссылок на java.lang.Object.Затем я раскомментировал «Шаг 3, проанализировать» и повторно запустил свой код с полученным результатом:

class Test {

    Test() {
        super();
    }
    private int x;
}

Обратите внимание, что на этом шаге были добавлены конструктор Test() и super(), что также соответствуетк объяснению для шага 3 [5] :

При анализе дерева можно найти ссылки на классы, которые необходимы для успешной компиляции, но которые не были явно указаны длякомпиляция.

Наконец, я раскомментировал Step 3, Generate, который создает файл Test.class.При вызове javap -c Test.class результирующий байт-код выглядит следующим образом:

class Test {
  Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
}

Поэтому я пришел к выводу, что шаг генерации байт-кода добавляет java.lang.Object связанную логику.

0 голосов
/ 07 марта 2019

Не совсем правильно.

Все классы расширяют Object , если они еще не расширяют другой класс , с одним исключением : java.lang.Object сам по себе не расширяет ни один класс.

Компилятор встраивает суперкласс java.lang.Object в файл класса, если в коде не указан другой суперкласс.

Вы даже можете увидеть его самостоятельно, если откроете файл .class в своем любимом редакторе, вы увидите строку java/lang/Object, встроенную в двоичные данные.

(Вы можете скомпилировать очень простой исходный файл, такой как public class A { }, чтобы лучше это увидеть)

...