简体   繁体   English

Java强制类如何扩展Object?

[英]How does Java force classes to extend Object?

How does this happen internally ? 这是如何在内部发生的? What mechanism is used? 使用什么机制? JNI, reflection or something different? JNI,反思还是别的什么? Does the compiler include the extends clause, perhaps? 编译器是否包含extends子句?

Not completely correct. 不完全正确。

All classes extend Object if they don't already extend another class , with one exception : java.lang.Object itself doesn't extend any class. 如果它们尚未扩展另一个类所有类都扩展Object ,但 有一个例外java.lang.Object本身不扩展任何类。

The compiler embeds the superclass java.lang.Object in the class file if the code doesn't specify another superclass. 如果代码没有指定另一个超类,编译器会在类文件中嵌入超类java.lang.Object

You can even see it yourself if you open the .class file with your favorite editor, you can see the string java/lang/Object embedded in binary data. 如果用你喜欢的编辑器打开.class文件,你甚至可以自己看到它,你可以看到嵌入在二进制数据中的字符串java/lang/Object

(You can compile a very simple source file like public class A { } to observe this best) (您可以编译一个非常简单的源文件,如public class A { }以便最好地观察它)

This is an interesting question about the internals of the java compiler. 这是一个关于java编译器内部的有趣问题。 I found a list of docs providing a high level view of javac [1] [2] [3] [4] . 我找到了一个文档列表,提供了javac [1] [2] [3] [4]的高级视图。 Source code for a specific implementation like OpenJdk can be found online too [source] . OpenJdk等特定实现的源代码也可以在线找到[来源]

Compilation consists of 3 high level steps [5] : 编译包含3个高级步骤[5]

  1. "parse and enter" “解析并输入”
  2. "annotation processing" “注释处理”
  3. "analyse and generate" “分析并生成”

I wrote some code to test these steps out using the Compiler Tree API which provides an interface to javac. 我编写了一些代码来使用Compiler Tree API来测试这些步骤,该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());
    }
}

Running the above code with Step 1 shows the following output: 使用步骤1运行上述代码显示以下输出:

class Test {
    private int x;
}

So the AST doesn't contain references to java.lang.Object . 所以AST不包含对java.lang.Object引用。 Next, I uncommented "Step 3, Analyse" and re-ran my code with the resulting output: 接下来,我取消注释“Step 3,Analyze”并使用生成的输出重新运行我的代码:

class Test {

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

Notice that the Test() constructor and super() was added in this step, which also corresponds to the explanation for Step 3 [5] : 请注意,在此步骤中添加了Test()构造函数和super() ,这也对应于步骤3 [5]的说明

While analysing the tree, references may be found to classes which are required for successful compilation, but which were not explicitly specified for compilation. 在分析树时,可以找到成功编译所需的类的引用,但是没有明确指定用于编译。

Finally, I uncommented Step 3, Generate , which creates the Test.class file. 最后,我取消注释Step 3, Generate ,它创建了Test.class文件。 Calling javap -c Test.class , the resulting bytecode is blelow : 调用javap -c Test.class ,得到的字节码是blelow:

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

So my conclusion is that the bytecode generation step adds the java.lang.Object related logic. 所以我的结论是字节码生成步骤添加了java.lang.Object相关的逻辑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM