Java编译究竟是如何进行的?

2022-08-31 15:24:08

被java编译过程弄糊涂了

好的,我知道这一点:我们编写java源代码,独立于平台的编译器将其转换为字节码,然后依赖于平台的jvm将其转换为机器代码。

所以从一开始,我们就编写java源代码。编译器 javac.exe 是一个.exe文件。这个.exe文件到底是什么?Java编译器不是用java编写的,那么为什么.exe文件来执行它呢?如果编译器代码是java编写的,那么编译器代码如何在编译阶段执行,因为执行java代码是jvm的工作。一种语言本身如何编译自己的语言代码?对我来说,这一切都像是先有鸡还是先有蛋的问题。

那么.class文件究竟包含什么?它是文本形式的抽象语法树,是表格信息,它是什么?

任何人都可以告诉我关于我的java源代码如何在机器代码中转换的清晰而详细的方法。


答案 1

好的,我知道这一点:我们编写java源代码,独立于平台的编译器将其转换为字节码,

实际上,编译器本身一个本机可执行文件(因此javac.exe)。没错,它将源文件转换为字节码。字节码与平台无关,因为它针对的是 Java 虚拟机。

然后依赖于平台的jvm将其转换为机器代码。

并非总是如此。至于Sun的JVM,有两个jvm:客户端和服务器。它们都可以,但肯定不必编译为本机代码。

所以从一开始,我们就编写java源代码。编译器 javac.exe 是一个.exe文件。这个.exe文件到底是什么?Java编译器不是用java编写的,那么为什么.exe文件来执行它呢?

此文件是包装的 Java 字节码。这是为了方便 - 避免复杂的批处理脚本。它启动一个 JVM 并执行编译器。exe

如果编译器代码是java编写的,那么编译器代码如何在编译阶段执行,因为执行java代码是jvm的工作。

这正是包装代码的作用。

一种语言本身如何编译自己的语言代码?对我来说,这一切都像是先有鸡还是先有蛋的问题。

没错,乍一看令人困惑。不过,这不仅仅是Java的习语。Ada的编译器也是用Ada本身编写的。它可能看起来像一个“先有鸡还是先有蛋的问题”,但实际上,这只是一个自举问题。

那么.class文件究竟包含什么?它是文本形式的抽象语法树,是表格信息,它是什么?

它不是抽象语法树。AST 仅由分词器和编译器在编译时使用,以表示内存中的代码。 file 就像一个程序集,但对于 JVM。反过来,JVM是一个抽象的机器,它可以运行专门的机器语言 - 仅针对虚拟机。在最简单的情况下,文件具有与普通程序集非常相似的结构。一开始是声明的所有静态变量,然后是一些extern函数签名表,最后是机器代码。.class.class

如果你真的很好奇,你可以使用“javap”实用程序深入研究类文件。以下是调用的示例(模糊处理)输出:javap -c Main

0:   new #2; //class SomeObject
3:   dup
4:   invokespecial   #3; //Method SomeObject."<init>":()V
7:   astore_1
8:   aload_1
9:   invokevirtual   #4; //Method SomeObject.doSomething:()V
12:  return

所以你应该已经知道它到底是什么。

任何人都可以告诉我关于我的java源代码如何在机器代码中转换的清晰而详细的方法。

我认为现在应该更清楚,但这里有一个简短的总结:

  • 调用指向源代码文件。javac的内部读取器(或分词器)读取您的文件并从中构建实际的AST。所有语法错误都来自此阶段。javac

  • 尚未完成其工作。当它具有AST时,真正的编译就可以开始了。它使用访问者模式来遍历 AST,并解析外部依赖项以向代码添加含义(语义)。成品将另存为包含字节码的文件。javac.class

  • 现在是时候运行这个东西了。使用.class文件的名称进行调用。现在 JVM 再次启动,但要解释你的代码。JVM 可能会,也可能不会将抽象字节码编译到本机程序集中。如果需要,Sun的HotSpot编译器与Just In Time编译相结合可以这样做。JVM 不断分析正在运行的代码,并在满足某些规则时重新编译为本机代码。最常见的是代码是第一个以本机方式编译的代码。java

编辑:如果没有,则必须使用类似如下内容调用编译器:javac

%JDK_HOME%/bin/java.exe -cp:myclasspath com.sun.tools.javac.Main fileToCompile

如您所见,它调用了 Sun 的私有 API,因此它绑定到 Sun JDK 实现。这将使构建系统依赖于它。如果切换到任何其他JDK(wiki列出了除Sun之外的5个),那么上面的代码应该更新以反映更改(因为编译器不太可能驻留在com.sun.tools.javac包中)。其他编译器可以用本机代码编写。

因此,标准方法是使用JDK发布包装器。javac


答案 2

Java编译器不是用java编写的,那么为什么.exe文件来执行它呢?

您从哪里获得此信息?可执行文件可以用任何编程语言编写,它是无关紧要的,重要的是它是将文件转换为文件的可执行文件。javac.java.class

有关.class文件的二进制规范的详细信息,您可能会发现 Java 语言规范中的这些章节很有用(尽管可能有点技术性):

您还可以查看虚拟机规范,其中涵盖:


推荐