当前位置: 首页 > 面试题库 >

java编译是如何进行的?

洪俊能
2023-03-14
问题内容

被Java编译过程弄糊涂

好的,我知道这一点:我们编写Java源代码,与平台无关的编译器将其转换为字节码,然后与平台相关的jvm将其转换为机器代码。

因此,从一开始,我们就编写Java源代码。编译器javac.exe是.exe文件。.exe文件到底是什么?Java编译器不是用Java编写的,然后为什么会有执行该文件的.exe文件?如果编译器代码是用Java编写的,那么在编译阶段如何执行编译器代码,因为jvm的工作是执行Java代码。语言本身如何编译自己的语言代码?对我来说,这似乎是鸡和鸡蛋的问题。

现在,.class文件到底包含什么?它是文本形式的抽象语法树,还是表格信息,它是什么?

谁能告诉我有关我的Java源代码如何在机器代码中转换的清晰详细的方法。


问题答案:

好的,我知道这一点:我们编写Java源代码,与平台无关的编译器将其转换为字节码,

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

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

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

因此,从一开始,我们就编写Java源代码。编译器javac.exe是.exe文件。.exe文件到底是什么?Java编译器不是用Java编写的,然后为什么会有执行该文件的.exe文件?

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

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

这正是包装代码的作用。

语言本身如何编译自己的语言代码?对我来说,这似乎是鸡和鸡蛋的问题。

是的,乍一看令人困惑。虽然,这不仅是Java的习惯用法。Ada的编译器也是用Ada本身编写的。它看起来像一个“鸡和鸡蛋的问题”,但实际上,这只是一个引导问题。

现在,.class文件到底包含什么?它是文本形式的抽象语法树,还是表格信息,它是什么?

它不是抽象语法树。AST仅由令牌生成器和编译器在编译时使用,以表示内存中的代码。.class该文件就像一个程序集,但用于JVM。JVM又是一种抽象机器,它可以运行专门的机器语言-
仅针对虚拟机。最简单的说,.class文件的结构与普通程序集非常相似。首先声明所有静态变量,然后是一些外部函数签名表,最后是机器代码。

如果您真的很好奇,可以使用“ javap”实用程序来深入研究classfile。这是调用的样本(混淆)输出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指向您的源代码文件的指针。javac 的内部 读取器 (或令牌生成器)读取文件,并根据该文件构建实际的AST。所有语法错误都来自此阶段。

  • javac还没有完成它的工作呢。如果具有AST,则可以开始进行真正的编译。它使用访问者模式遍历AST并解决外部依赖关系,以在代码中html" target="_blank">添加含义(语义)。成品另存为.class包含字节码的文件。

  • 现在该运行该东西了。您java使用.class文件的名称进行调用。现在,JVM重新启动,但可以 解释 您的代码。JVM可能会或可能不会将您的抽象字节码编译到本机程序集中。如果需要,可以结合使用Sun的HotSpot编译器和即时编译。如果满足某些规则,则JVM会不断对正在运行的代码进行概要分析,并重新编译为本机代码。最常见的是, 代码是第一个本地编译的代码。

编辑:如果没有,则javac必须使用类似于以下的方法来调用编译器:

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

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

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



 类似资料:
  • 问题内容: 我正在尝试反编译 Java项目(.jar)文件,并且能够从其中获取.java文件。现在如何将其编译回来?我可以将.java文件作为单个文件添加到Netbeans。但是如何将其作为项目添加并编译呢?该项目是JavaFX项目。所以请帮我。 问题答案: 有很多方法可以实现此目的,但是我认为您不能像这样直接在框内(在本例中为开箱)将项目导入jar中。 我们可以使用最基本的技术(我承认有点脏),

  • 问题内容: 我在编译代码时收到一条消息: 如何重新编译? 问题答案: 在javac的命令行上指定它: javac -Xlint:unchecked 或者,如果您使用的是Ant,请修改您的javac目标 如果您使用的是Maven,请在

  • 我在读Rust编程语言书,偶然发现了一个简单的表达式: match如何处理不同类型的表达式?E、 g.第一个臂将简单地“return”

  • 错误 我正在编译SimpleCompiletest.java并得到这个错误。救命啊!!!

  • 然而,原始的apk是由一个密钥库(在eclipse IDE上)签名的,这个不是,我如何用它在eclipse之外的原始keystone文件正确地签名呢?

  • 问题内容: 在计算机上安装Linux系统时,我不太了解Linux内核的编译过程。 以下是使我感到困惑的一些事情: 内核是用C编写的,但是如何在未安装编译器的情况下编译内核? 如果在编译内核之前在我的机器上安装了C编译器,那么在没有安装编译器的情况下如何编译该编译器本身? 几天来我都很困惑,感谢您的回复。 问题答案: Linux盒的第一轮二进制文件建立在其他Linux盒上(可能)。 第一个Linux