「java」コマンドはJavaプログラムをコンパイルしますか?


145

インターネット上のほとんどのウェブサイトは言う:

" javacコマンドを使用して.javaファイルをコンパイルします。次に、javaコマンドを使用して実行します"

しかし、今日、Javaプログラムを実行せずに実行しようとしたjavacところ、奇妙な結果が得られました。

次のファイルの内容は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のバージョンは次のとおりです。

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)

11
どのバージョンを使用していますか?私は彼らがJava 9でJavaコンソールを導入したと思います、そしてそれはあなたが経験したものかもしれません。
Matthieu

6
クラス名とファイル名を一致させる必要があります。これはJava標準です。ファイル名をに変更Myclass.javaし、コマンドラインから次のようにコンパイルして、このjavac Myclass.javaように実行しjava Myclassます。
unnsse

6
はい、javacあなたがソースコードを展開したくない場合は、まだコンパイルに使用されるか、それ以上の単一ファイルよりも持っている(ドキュメントjava:ソース・ファイルのオプションにのみ単一のソースファイルのプログラムを起動するために使用される。)
user85421

@Matthieu「java -version」の出力は次のとおりです。openjdkバージョン「12.0.2」2019-07-16 OpenJDKランタイム環境(ビルド12.0.2 + 10)OpenJDK 64ビットサーバーVM(ビルド12.0.2 + 10、混合モード)
milad

1
@Milad-何が起こるか-これjavacはJavaソースをJVM固有の解釈済みバイトコードにコンパイルし、javaコマンドはそれをJVMのClassLoader内にロードします。
unnsse

回答:


188

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)

更新:

@BillKが指摘したように、OPは次のことも尋ねました。

なぜjavacコマンドが必要なのですか?

私たちが必要javacとする理由は.class、コードを現在のように作成、テスト、配布、実行、共有などできるようにファイルを作成することです。JEP 330の動機は、他の既存の用途を変更することなく、「Javaの学習の初期段階、および小さなユーティリティプログラムを作成するとき」を容易にすることでした。



詳細については@CarlosHeubergerに感謝します。私はそれがJavaの11で導入されたことを反映するために、私の答えに小さな編集をした
カーン

7
Javaの8(彼らが落ちだ@Spikatrix 1.1.8新しいリリースでは)
muru

1
なぜjavacが必要なのかという質問には答えませんでした。Javaは、提供された単一のファイルと以前にコンパイルされたファイルでのみ動作すると思います。呼び出すファイルから、使用する他のすべてのファイルをコンパイルする必要があると思います。
ビルK

2
この回答では、この新しいメソッドが原因でファイル名とクラス名のエラーが発生しない理由については触れていませんjavac
sebrockm

52

Java 11を実行している場合は、単一のソースファイルを実行できる新機能があります。シングルソースコンパイラーは、クラス名とファイル名の点でより無差別です。そのため、この方法で実行できますが、正常にコンパイルできません。

以前のバージョンのJavaを使用している場合は、特にクラス名に関連するコンパイルエラーのため、現在のhello.javaはコンパイルされません。したがって、java hello.javaを呼び出してもコードがコンパイルされなかったため、コンパイルできませんでした。

javaコマンドを実行するときに、以前にコンパイルしたコードを実行していた可能性が最も高いようです。


ありがとう、Javaバージョンは次のとおりです:openjdkバージョン "12.0.2" 2019-07-16 OpenJDKランタイム環境(ビルド12.0.2 + 10)OpenJDK 64ビットサーバーVM(ビルド12.0.2 + 10、混合モード)
milad

5
ソースファイルモードを使用して単一ファイルのソースコードプログラムを起動する場合のチェック:「コンパイラーは、JLSの最後に定義されたオプションの制限を適用しません?? 7.6、名前付きパッケージのタイプが名前がタイプ名とそれに続く.java拡張子から構成されます。
user85421

2
JavaスクリプトAPIとJavaシングルファイルソースコードプログラムの起動(JEP 330)は、2つの完全に独立したものであり、まったく関係のないものです。
デビッドコンラッド

@DavidConrad、それに応じて表現を更新。ありがとう。
エヴァン

入力@TJCrowderに感謝します。しかし、私はそれをそのまま書くつもりだったとかなり確信しています。また、リンクの2番目の定義:無差別とは、さまざまなものを含むことを意味します。
エヴァン

6

このエラーが発生する理由を回答するには、ファイルのクラス名がファイルのクラス名と一致する必要があります basename

このコードを従来ので機能させるには、2つのオプションがありますjavacjavaシーケンス:

  1. クラスの名前をpublic class Helloまたはに変更します

  2. 名前hello.javaをに変更しmyclass.javaます。

javaJava 11 のインタープリターはこの要件を課しません。を含むmainクラスは、ファイルの最初のクラスである限り、任意の名前を付けることができます。これは主に初心者の学習プロセスを容易にし、シバンで「Javaスクリプト」を可能にすることを目的としていました(参照)。


5

はい、しかしあなたがおそらく意味する方法ではありません。

あなたが使うとき javacコマンドをて.javaファイルを.classファイルにコンパイルすると、出力はバイトコードと呼ばれます。バイトコードは、Java仮想マシン仕様に基づく理論上のCPUのマシンコード(ネイティブ命令)です。

この仮想CPU仕様は、仕様が作成された時点で一般的なCPUのタイプの平均のようなものです。このため、多くの異なるタイプのCPUに近く、複数のCPUタイプで同じJava .classファイルを実行するのが簡単になります。

Javaが最初に起動されたとき、javaコマンドは.classファイルを読み取り、バイトコード命令を一度に1つずつ解釈し、実際に実行されていたCPUの同等のネイティブ命令にそれらをマッピングします。これは機能しましたが、特に速くはありませんでした。これを改善するために、ジャストインタイム(JIT)コンパイルがJavaランタイムに追加されました。

JITを使用すると、javaコマンドはバイトコードを受け取り、それを実行しているCPUのネイティブ命令に再度コンパイルします。最新のJavaランタイムは、JITがバックグラウンドでコンパイルしているときにバイトコードの解釈を開始し、準備ができたらコンパイル済みのネイティブ命令に切り替え、実行中のアプリケーションのプロファイルを作成し、さまざまな最適化でバイトコードを再コンパイルして、可能な限り最高のパフォーマンスを得る傾向があります。

編集(反対投票者を和らげるため):

したがって、特定のケースでは(v11より新しいJREを実行している場合)、コードは(少なくとも)2回コンパイルされます。

  1. バイトコードへの単一の.javaファイルとして
  2. JITコンパイラを介してバイトコードを解釈します(ただし、helloWorldの場合、コンパイルされたネイティブコードを実行する時間が実際にはない可能性があります)

7
これは質問の答えにはなりません。
デビッドコンラッド

2
@DavidConradしかし、そうです!「 'java'コマンドはJavaプログラムをコンパイルしますか?」に対する答え hardlibがここに与える理由により、「有り」です。バイトコードをネイティブ命令にジャストインタイムでコンパイルします(重要なプログラムの場合、標準的な設定で)。
ピーター-モニカを復活させる

コンパイルは必須ですか?歴史的に、Javaバイトコードは解釈できました。JITコンパイルはオプションでした。
MSalters

JITはmixed-mode、バージョン出力に示されているように、これらの日(非常に長い時間)にデフォルトでオンになっています
hardillb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.