跳转到内容

编译

75% developed
来自维基教科书,开放的书籍,开放的世界

导航 入门 主题: v  d  e )


在 Java 中,程序不会编译成可执行文件;它们被编译成字节码(如之前所述),然后 JVM(Java 虚拟机)在运行时执行它。当我们使用 javac 编译器时,Java 源代码被编译成字节码。字节码以 .class 文件扩展名保存到磁盘上。当程序要运行时,字节码会使用即时 (JIT) 编译器进行转换。结果是机器码,然后被送入内存并执行。

Java 代码需要编译两次才能执行

  1. Java 程序需要编译成字节码。
  2. 当字节码运行时,它需要被转换成机器码。

Java 类/字节码在第一次需要时被 JVM 编译成机器码并加载到内存中。这与 C/C++ 等其他语言不同,在这些语言中,程序需要编译成机器码并链接以创建可执行文件,然后才能执行。

快速编译过程

[编辑 | 编辑源代码]

要执行您的第一个 Java 程序,请按照以下说明进行操作

1. 如果您已成功安装并配置好系统以使用 Java,如这里所述,则继续执行。
2. 打开您首选的文本编辑器 - 这是您在安装 Java 平台时设置的编辑器。
例如,在 Windows 上使用 记事本Notepad++;在 Linux 上使用 GeditKateSciTE;或者,在 Mac OS 上使用 XCode 等。
3. 在新的文本文档中编写以下代码行
Computer code 代码清单 2.5: HelloWorld.java
public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello World!");
  }
}
4. 将文件保存为 HelloWorld.java - 您的文件名应与您的类定义的名称相同,并在后面加上 .java 扩展名。此名称是区分大小写的,这意味着您需要将类定义名称中的字母大小写与您保存的文件名大小写保持一致。
5. 接下来,打开您首选的命令行应用程序。
例如,在 Windows 上使用 命令提示符;在 Linux 和 Mac OS 上使用 终端
6. 在命令行应用程序中,导航到您刚刚创建文件的目录。如果您不知道如何执行此操作,请考虑阅读我们的命令行应用程序速成课程,适用于WindowsLinux
7. 使用以下命令编译 Java 源文件,如果您需要,您可以复制粘贴。
Computer code 编译
javac HelloWorld.java
Warning 如果您得到类似于 error: cannot read: HelloWorld.java 1 error 的错误消息,则您的文件不在当前文件夹中或拼写错误。您是否使用cd (change directory) 命令在命令提示符中导航到程序所在位置?

如果您得到另一个以 1 error... errors 结尾的消息,则您的代码中可能存在错误。您是否确定所有单词的拼写都正确,并且大小写与所示完全一致?分号和括号是否在适当的位置?您是否缺少引号?通常,现代 IDE 会尝试在这种情况下将整个源代码着色为引号。

如果您的计算机发出蜂鸣声,则您的 HelloWorld.java 中可能包含非法字符。

如果没有在同一个文件夹中创建 HelloWorld.class 文件,则您遇到了错误。您是否正确启动了 javac 程序?

8. 一旦编译器返回到提示符,请使用以下命令运行应用程序
Computer code 执行
java HelloWorld
Warning 如果您得到类似于 Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld 的错误消息,则 HelloWorld.class 文件不在当前文件夹中或拼写错误。

如果您得到类似于 Exception in thread "main" java.lang.NoSuchMethodError: main 的错误消息,则您的源文件可能编写错误。

9. 上面的命令应导致您的命令行应用程序显示以下结果
Computer code 输出
Hello World!
如果程序没有正确执行,请在本章的讨论页面中寻求帮助.

自动编译依赖类

[编辑 | 编辑源代码]

在 Java 中,如果您使用了对任何其他 java 对象的引用,那么该对象的类将被自动编译,如果它还没有被编译的话。这些自动编译是嵌套的,并且会一直持续到所有运行程序所需的类都被编译完成。因此,通常只编译高级类就足够了,因为所有依赖类都会被自动编译。

Computer code 主类编译
javac ... MainClass.java

但是,如果您程序使用反射来创建对象,或者您正在为 servlet 或“jar”包编译,则不能依赖此功能。在这些情况下,您应该列出这些类以进行显式编译。

Computer code 主类编译
javac ... MainClass.java ServletOne.java ...

包、子目录和资源

[编辑 | 编辑源代码]

每个 Java 顶级类都属于一个包(在关于的章节中介绍)。这可以在文件开头的package语句中声明;如果缺少该语句,则该类属于未命名包。

为了编译,文件必须位于正确的目录结构中。包含未命名包中类的文件必须位于当前/根目录中;如果类属于某个包,则它必须位于与包同名的目录中。

惯例是,与包相对应的包名和目录名仅包含小写字母。

顶级包

[编辑 | 编辑源代码]

具有此包声明的类

Example 代码节 2.1:包声明
package example;

必须位于名为example的目录中。

具有此包声明的类

Example 代码节 2.2:带子包的包声明
package org.wikibooks.en;

必须位于名为en的目录中,该目录必须是wikibooks的子目录,而wikibooks又必须是org的子目录,最终形成Linux上的org/wikibooks/en或Windows上的org\wikibooks\en

Java 程序通常包含非代码文件,例如图像和属性文件。这些通常称为资源,并存储在它们所用类的本地目录中。例如,如果类com.example.ExampleApp使用icon.png文件,则该文件可以存储为/com/example/resources/icon.png。当程序编译时,这些资源会带来问题,因为javac不会将它们复制到.class文件正在编译到的位置(见上文);程序员需要自己移动资源文件和目录。

文件名大小写

[编辑 | 编辑源代码]

Java 源文件名必须与文件包含的公共类名相同。每个文件只能定义一个公共类。Java 类名和源文件名都区分大小写。

类名命名规范是首字母大写。

编译器选项

[编辑 | 编辑源代码]

调试和符号信息

[编辑 | 编辑源代码]
Clipboard

待办事项
完成本节。


要调试到 Java 系统类(如 String 和 ArrayList),您需要使用编译了“调试信息”的 JRE 特殊版本。JDK 中包含的 JRE 提供了此信息,但常规 JRE 则没有。常规 JRE 不包含此信息,以确保更好的性能。


   Modern compilers do a pretty good job converting your high-level code, with its nicely indented and nested control structures and arbitrarily typed variables into a big pile of bits called machine code (or bytecode in case of Java), the sole purpose of which is to run as fast as possible on the target CPU (virtual CPU of your JVM). Java code gets converted into several machine code instructions. Variables are shoved all over the place – into the stack, into registers, or completely optimized away. Structures and objects don’t even exist in the resulting code – they’re merely an abstraction that gets translated to hard-coded offsets into memory buffers.
   So how does a debugger know where to stop when you ask it to break at the entry to some function? How does it manage to find what to show you when you ask it for the value of a variable? The answer is – debugging information.
   Debugging information is generated by the compiler together with the machine code. It is a representation of the relationship between the executable program and the original source code. This information is encoded into a pre-defined format and stored alongside the machine code. Many such formats were invented over the years for different platforms and executable files.


符号信息:符号解析在类加载时在链接解析步骤中完成。它是用直接引用替换类型中的符号引用的过程。它是通过在方法区中搜索以定位所引用实体来完成的。

JIT 编译器

[编辑 | 编辑源代码]

即时 (JIT) 编译器是将字节码转换为机器码的编译器。它一次编译字节码,并且编译后的机器码会反复使用,以加快执行速度。早期的 Java 编译器每次使用字节码时都会将其编译为机器码,但更现代的编译器会缓存此机器码以在机器上重复使用。即使如此,Java 的 JIT 编译仍然比“解释语言”更快,在解释语言中,代码每次使用时都从高级语言而不是从字节码编译。

标准 JIT 编译器按需运行。当方法被反复调用时,JIT 编译器会分析字节码并生成高效的机器码,运行速度非常快。JIT 编译器足够智能,可以识别代码是否已编译,因此,随着应用程序的运行,编译只会根据需要发生。随着 Java 应用程序的运行,它们往往会变得越来越快,因为 JIT 可以对代码进行运行时分析和优化以满足执行环境。运行不频繁的方法或代码块接收的优化较少;运行频繁的方法或代码块(所谓热点)接收的分析和优化更多。


华夏公益教科书