'java'命令是否编译Java程序?

问题描述 投票:61回答:3

[Internet上的任何网站都说:我们应该使用javac编译.java文件,然后使用java命令运行它。但是今天我试图在没有javac的情况下运行Java程序,但结果却很奇怪。

我的文件名为hello.java,包含:

public class Myclass {
 public  static void main(String[] args){
    System.out.println("hello world");
  }
}

我执行了此命令,这给了我一个合理的错误:

$ javac hello.java
hello.java:1: error: class Myclass is public, should be declared in a file named Myclass.java
public class Myclass {
       ^
1 error

但是当我在没有javac的情况下运行它时,它没有任何错误地执行!

$ java hello.java
hello world

java命令是否也编译程序?如果答案是肯定的,为什么我们需要javac命令?

我的java版本是:

$ java -version
openjdk version "12.0.2" 2019-07-16
OpenJDK Runtime Environment (build 12.0.2+10)
OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode)
java javac
3个回答
94
投票

在Java 11之前,要运行代码,必须先对其进行编译,然后才能运行它。这是一个例子:

javac test.java
java test

自Java 11起,您仍然可以执行javac + java,也可以单独运行java来编译和自动运行代码。请注意,将不会生成.class文件。这是一个例子:

java test.java

如果运行java -help,则会看到各种允许的用法。这是我的机器上的样子。最后一个是您遇到的:java [options] <sourcefile> [args],它将“执行单个源文件程序”。

$ java -help
Usage: java [options] <mainclass> [args...]
           (to execute a class)
   or  java [options] -jar <jarfile> [args...]
           (to execute a jar file)
   or  java [options] -m <module>[/<mainclass>] [args...]
       java [options] --module <module>[/<mainclass>] [args...]
           (to execute the main class in a module)
   or  java [options] <sourcefile> [args]
           (to execute a single source-file program)

30
投票

如果您正在运行Java 11,有一项新功能,允许执行单个源文件。就类名与文件名而言,单源编译器更为繁琐,因此您可以运行但无法成功编译。

[如果您使用的是Java的早期版本,,则由于编译错误,尤其是围绕类名,当前的hello.java无法编译。因此,绝对不可能调用java hello.java来编译您的代码,因为它不会编译。

似乎最有可能您在执行java命令时正在运行一些先前编译的代码。


4
投票

是,但不是您可能要说的那样。

[当您使用javac命令将.java文件编译为.class文件时,输出为字节码。字节码是基于Java虚拟机规范的理论CPU的机器代码(本机指令)。

此虚拟CPU规范是编写规范时常见的CPU类型的平均值。因此,它接近许多不同类型的CPU,从而使在多个CPU类型上运行相同的Java .class文件更加容易。

[Java首次启动时,java命令将读取.class文件并一次解释一个字节码指令,然后将它们映射到等效的本机指令,以了解其实际运行的CPU。这行得通,但并不是特别快。为了改善这一点,已将准时(JIT)编译添加到Java运行时。

使用JIT,java命令获取字节码,然后将其再次编译为正在运行的CPU的本机指令。现代Java运行时倾向于在后台进行JIT编译时开始解释字节码,并在就绪时切换到已编译的本机指令,还将分析正在运行的应用程序,然后使用不同的优化再次重新编译字节码,以获得最佳性能。] >

编辑(以安定下来的选民):因此,在您的特定情况下(当您运行的是比v11更新的JRE时),代码将(至少)编译两次

  1. 作为单个.java文件转换为字节码
  2. 通过JIT编译器解释字节码(尽管对于helloWorld,它可能实际上没有时间运行任何已编译的本机代码)
© www.soinside.com 2019 - 2024. All rights reserved.