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

时间:2010-08-04 15:12:23

标签: java compiler-construction jvm

被java编译过程困惑

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

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

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

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

9 个答案:

答案 0 :(得分:58)

  

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

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

  

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

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

  

所以从一开始,我们就编写了java源代码。编译器javac.exe是一个.exe文件。这个.exe文件究竟是什么?是不是用java编写的java编译器,那怎么会有执行它的.exe文件?

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

  

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

这正是包装代码的作用。

  

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

真的,乍看之下令人困惑。虽然,这不仅仅是Java的习语。 Ada的编译器也是用Ada编写的。它可能看起来像“鸡蛋和鸡蛋问题”,但事实上它只是引导问题。

  

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

它不是抽象语法树。 AST仅在编译时由tokenizer和编译器用于表示内存中的代码。 .class文件就像一个程序集,但是对于JVM。反过来,JVM是一个可以运行专用机器语言的抽象机器 - 仅针对虚拟机。最简单的是,.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。 javac的内部 reader (或tokenizer)读取你的文件并从中构建一个实际的AST。所有语法错误都来自此阶段。

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

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

编辑:如果没有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包装器。

答案 1 :(得分:15)

  

是不是用java编写的java编译器,那怎么会有执行它的.exe文件?

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

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

您还可以查看涵盖的Virtual Machine Specification

答案 2 :(得分:11)

  

编译器javac.exe是一个.exe文件。   这个.exe文件究竟是什么?是不是   用java编写的java编译器,   那怎么会有.exe文件   执行它?

Java编译器(至少是Sun / Oracle JDK附带的编译器)确实是用Java编写的。 javac.exe只是一个处理命令行参数的启动程序,其中一些参数传递给运行编译器的JVM,其他传递给编译器本身。

  

如果编写的代码是   java,那么编译器代码是怎么来的   在编译阶段执行,   因为它是jvm的工作   执行java代码。一个语言怎么样   本身编译自己的语言代码?   这一切看起来像鸡肉和鸡蛋   我的问题。

许多(如果不是大多数)编译器都是用他们编译的语言编写的。显然,在某个早期阶段,编译器本身必须由其他东西编译,但在“bootstrapping”之后,任何新版本的编译器都可以由旧版本编译。

  

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

类文件格式的详细信息在Java Virtual Machine specification

中描述

答案 3 :(得分:5)

嗯,javac和jvm通常都是原生二进制文件。它们是用C语写的。用Java编写它们当然是可能的,只需要首先需要本机版本。这称为“引导捆绑”。

有趣的事实:编译为本机代码的大多数编译器都是用他们自己的语言编写的。但是,它们都必须首先使用另一种语言编写本机版本(通常为C)。相比之下,第一个C编译器是用汇编程序编写的。我认为第一个汇编程序是用机器代码编写的。 (或者,using butterflies;)

.class文件是javac生成的字节码。它们不是文本的,它们是类似于机器代码的二进制代码(但是,使用不同的指令集和架构)。

jvm在运行时有两个选项:它可以解释字节代码(假装是CPU本身),也可以JIT(及时)将其编译为本机机器代码。当然,后者更快,但更复杂。

答案 4 :(得分:3)

.class文件包含字节码排序非常high-level Assembly。编译器很可能用Java编写,但JVM必须编译为本机代码以避免鸡/蛋问题。我相信它是用C语言编写的,标准库的低级也是如此。当JVM运行时,它会执行即时编译,将该字节码转换为本机指令。

答案 5 :(得分:2)

简短说明

在文本编辑器上编写代码,以编译器理解的格式保存 - “。java”文件扩展名, javac (java编译器)将其转换为“。class”格式文件(字节代码 - 类文件)。 JVM在它所在的操作系统上执行.class文件。

长解释

始终记住java不是操作系统识别的基本语言。 Java源代码由称为 Java虚拟机(JVM)的转换程序解释为操作系统。 JVM无法理解您在编辑器中编写的代码,它需要编译代码。这就是编译器的用武之地。

每个计算机进程都沉迷于内存操作。我们不能在文本编辑器中编写代码并进行编译。我们需要将它放在计算机的内存中,即在编译之前保存它。

javac(java编译器)如何将保存的文本识别为要编译的文本? - 我们有一个编译器识别的单独文本格式,即 .java 。将文件保存为.java扩展名,编译器将识别它并在询问时编译它。

编译时会发生什么? - 编译器是该过程中涉及的第二个翻译器(不是技术术语),它将用户理解的语言(java)转换为JVM理解语言(字节代码 - .class格式)。

编译后会发生什么? - 编译器生成JVM理解的.class文件。然后执行该程序,即.class文件由JVM在操作系统上执行。

你应该知道的事实

1)Java不是多平台 独立于平台

2)JVM是使用 C / C ++ 开发的。人们称Java为比C / C ++更慢的语言的原因之一

3)Java字节代码(.class)是“汇编语言”,是JVM理解的唯一语言。在编译或生成的字节代码上生成.class文件的任何代码都可以在JVM上运行。

答案 6 :(得分:1)

Windows在安装Java运行时之前不知道如何调用Java程序,并且Sun选择使用本机命令来收集参数,然后调用JVM而不是将jar后缀绑定到Java引擎。

答案 7 :(得分:-1)

编译器最初用C语言编写,带有C ++位,我认为它仍然是(为什么你认为编译器也是用Java编写的?)。 javac.exe只是编译器的C / C ++代码。

作为一个侧面点,你可以在java中编写编译器,但你是对的,你必须避免鸡和蛋的问题。为此,您通常会在C语言中编写一个或多个引导工具,以便能够编译编译器。

.class文件包含字节码,javac编译过程的输出,这些是告诉JVM要做什么的指令。在运行时,这些字节码已转换为本机CPU指令(机器代码),因此它们可以在JVM下的特定硬件上执行。

为了使这一点复杂化,JVM还优化并缓存从字节码生成的机器代码,以避免重复翻译它们。这称为JIT编译,在程序运行并且正在解释字节码时发生。

答案 8 :(得分:-4)

  1. .java文件
  2. 编译器(JAVA BUILD)
  3. 的.class(字节码)
  4. JVM(系统软件通常使用'C'构建)
  5. 操作平台
  6. PROCESSOR