【问题标题】:Does Java have to be compiled to bytecode?Java是否必须编译为字节码?
【发布时间】:2018-05-13 01:07:57
【问题描述】:

Java 语言规范是否要求将 Java 编译为 Java 字节码?

据我了解,情况并非如此:

JLS 1

编译时间通常包括 将程序翻译成与机器无关的字节码 [re​​presentation.

[...]

Java 编程语言通常编译为字节码指令 Java 虚拟机规范、Java SE 中定义的集合和二进制格式 9 版。

(强调我的)

我在规范中找不到任何其他提及“字节码”或“字节码”的地方。

这是否意味着所有字节码操作在技术上都没有被 JLS 定义的“Java 语言”所涵盖,并且在技术上依赖于实现细节?

【问题讨论】:

  • 有待验证,但这可能是在 JVM 规范中,而不是在语言规范中。另外,从 Java 9 开始,JShell(我认为是这个名字)允许在 shell 中执行 java 代码,而无需编译。
  • @AxelH "this" 是字节码操作?我不认为 JVM 规范可以指定 Java 必须 被编译为 Java 字节码。
  • 确实,Java 语言可以以任何方式编译。尽管JVM specification 确实涵盖了字节码。 “Java 虚拟机对 Java 编程语言一无所知,只知道一种特定的二进制格式,即类文件格式。类文件包含 Java 虚拟机指令(或字节码)和符号表,以及其他辅助信息。”
  • @AxelH 我还没有检查过 JShell,但这不就是 JDK 发行版的产物吗?此外,仅仅因为没有明确的编译为字节码的步骤并不意味着 Jshell 不能这样做。
  • @phant0m 我发现在使用它的工具上找到字节码规范更符合逻辑。你能详细说明“”this“是字节码操作吗?”我不明白。 (JShell 仅供参考,这很可能是编译的,但以他自己的方式)

标签: java bytecode jls language-implementation


【解决方案1】:

您注意到了,“正常”一词以及 JLS 中没有任何字节码描述的目的是为了将 Java 编程语言定义为尽可能独立于执行环境。不过,这并不容易:

Relationship to Predefined Classes and Interfaces

如上所述,本规范通常引用 Java SE 平台 API 的类。特别是,某些类与 Java 编程语言有着特殊的关系。示例包括诸如ObjectClassClassLoaderStringThread 等类,以及包java.lang.reflect 中的类和接口等。本规范限制了此类类和接口的行为,但没有为它们提供完整的规范。读者可参考 Java SE 平台 API 文档。

因此,本规范没有详细描述反射。许多语言结构在核心反射 API (java.lang.reflect) 和语言模型 API (javax.lang.model) 中都有类似物,但这里通常不讨论这些。例如,当我们列出可以创建对象的方式时,我们通常不包括 Core Reflection API 可以完成此操作的方式。读者应该了解这些额外的机制,即使它们没有在文中提及。

所以 Java 编程语言不仅仅是 JLS,它还是 Java SE 平台 API。在那里,我们有提到的ClassLoader 类的defineClass 方法,接受类文件格式的输入。因此,即使我们使用字节码格式的类文件以外的其他部署方式,完全兼容的环境也必须在此支持该格式。请注意,Java 9 引入了 another method accepting input in the class file format,它甚至不需要反射或实现自定义类加载器。

这排除了 JavaME,它没有 JLS 提到的这些 API 工件,否则,我们已经有一个 Java 环境不支持字节码操作的示例。

但这仍然不能完全回答字节码操作是否是非语言的问题,说到 JavaSE 或 EE。即使标准 API 提供了对字节码格式的支持,字节码操作也取决于实现细节,要么是不强制支持的 Instrumentation API,要么通过处理已部署形式的已编译类文件,如文件层次结构、jar 文件或模块文件,都不能保证是应用程序的部署形式(如开头所述)。因此,确实不可能实现 保证每个 可能的 Java 环境一起使用的字节码操作工具,尽管您必须竭尽全力创建一个 @ 987654323@…

【讨论】:

  • 我目前正在浏览 JLS,目前正在阅读 JLS 第 12 章和第 13 章。它还讨论了类加载器,以及从 JVM 的角度总体上关于 Java 程序的执行,尽管它没有明确说它必须在一个上运行。这似乎进一步强调了您的观点,即“这并不容易”
【解决方案2】:

JSL 不必知道 JVM 将如何读取它,它只描述 Java 语言。 JDK中提供的编译器(JAVAC)做链接,但它不是语言本身的一部分

Oracle 的 JDK 软件包含一个从 Java 编程语言编写的源代码到 Java 虚拟机指令集的编译器

The Java™ Programming Language Compiler,,我们可以找到相同的解释:

Java 编程语言编译器 javac 读取用 Java 编程语言编写的源文件,并将它们编译成字节码类文件。或者,编译器还可以使用 Pluggable Annotation Processing API 处理在源文件和类文件中找到的注释。编译器是一个命令行工具,但也可以使用 Java Compiler API 调用。 编译器接受 Java 语言规范 (JLS) 定义的源代码并生成 Java 虚拟机规范 (JVMS) 定义的类文件

所以 JAVAC 命令主要是规范之间的桥梁。

  • 输入:JLS 中的 .java 描述
  • 输出:JVMS 中的 .class 描述。

您可以通过查看Jave Virtual Machine Specification 找到一些信息。

Java 虚拟机对 Java 编程语言一无所知,只知道一种特定的二进制格式,即类文件格式。类文件包含 Java 虚拟机指令(或字节码)和符号表,以及其他辅助信息。

(我想找到相反的说法,Java语言对Java虚拟机语言一无所知......)

在该规范的后面,我们发现了有关类格式以及语言如何翻译成该指令列表的更多信息。

【讨论】:

    猜你喜欢
    • 2017-06-07
    • 1970-01-01
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 2018-01-31
    • 2013-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多