【Java】プログラムの実行手順(コンパイルと起動)

Java

Javaプログラム実行の基本

Javaプログラムを実行するには、大まかに次の手順を踏む必要があります。

  1. ソースファイル( .java )の作成 = コーディング
  2. クラスファイル( .class )の作成 = コンパイル
  3. クラスファイル( .class )の起動 = Javaプログラムの実行

Javaプログラム実行の手順

開発環境と実行環境の準備

Javaプログラムの実行にあたり、まずはjavaコマンド及びjavacコマンドを実行できるようにしておく必要があります。コマンドプロンプトを開き、javac --version java --version でバージョン情報が出力されることを確認してください。

認識されていないエラーが出力された場合、コマンドの設定手順はこちらです。

以降の手順では、プログラムの実行に必要なjavaコマンドと、開発ツールの一つであるコンパイラ(=javacコマンド)の両方が必要となります。javaコマンドは実行できるものの、javacコマンドは実行できないという場合、JREを使用している可能性があるため、JDKをダウンロードして使用するようにしてください。

JDKとJREについては以下で簡単に触れています。

ソースファイルの作成

まずはソースファイル( .java )の作成、すなわちコーディングを行います。この例では「Hello World」を出力する以下の Main.java を使用していきます。

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

このファイルを任意のディレクトリに配置して、次の手順へ進みます。

クラスファイルの作成

次にクラスファイル( .class )の作成、すなわちコンパイルを行います。これにはコンパイラ(=javacコマンド)を使用します。

まずjavacコマンド実行のため、Main.java を配置したディレクトリでコマンドプロンプトを開きます。( 【Tips】エクスプローラからコマンドプロンプトを開く方法

続いて、作成した Main.java を引数に指定してjavacコマンドを実行します。

$ javac Main.java

これがコンパイラ(=javacコマンド)によるソースファイルのコンパイルです。特にオプションを指定していなければ、同じディレクトリにクラスファイルが作成されることを確認できます。

クラスファイルの起動

最後にクラスファイル( .class )の起動、すなわちJavaプログラムの実行を行います。

javacコマンドで作成したクラスファイルに対して、今度はjavaコマンドを使用しますが、この時、引数には拡張子を含めずにクラスファイル名のみを指定するようにします。( ※注意

$ java Main
Hello World

ここでは、以下のような .java.class との対比に重点を置いて説明するため、「javaコマンドの引数にはクラスファイル名を、拡張子を含めずに、指定する。」と表現しました。

  • ソースファイルを対象とするコマンド / クラスファイルを対象とするコマンド
  • javacコマンドの使用 / javaコマンドの使用

しかしjavaコマンドのヘルプからも確認できる通り、正確には、指定するのはクラスファイル名ではなくクラス名であるため、この表現は完全に誤りです。以下の通り、<mainclass> を指定するよう説明があり、<classfile> のような記述はどこにもありません。

$ java --help
使用方法: java [options] <mainclass> [args...]
           (クラスを実行する場合)
   または  java [options] -jar <jarfile> [args...]
           (jarファイルを実行する場合)
   または  java [options] -m <module>[/<mainclass>] [args...]
       java [options] --module <module>[/<mainclass>] [args...]
           (モジュールのメイン・クラスを実行する場合)
   または  java [options] <sourcefile> [args]
           (ソースファイル・プログラムを実行する場合)

クラス・ファイルを起動するには:
java [optionsmainclass [args …]

ツール・ガイド > javaコマンド > シノプシス

従って正しくは、「javaコマンドの引数には、FQCN(完全修飾クラス名)を指定する。」となります。

デフォルトでは、javaコマンドのオプションではない最初の引数は、コールされるクラスの完全修飾名です。

ツール・ガイド > javaコマンド > 説明

Javaはクラス名と同じファイル名にする必要があるため、そこに定義されたクラス名と、拡張子を除いたクラスファイル名は結果として同じものとなります。しかし指す意味は全く異なるため、コンパイル時(javacコマンドの引数)には「ソースファイル名」を、実行時(javaコマンドの引数)には「完全修飾クラス名」を、それぞれ指定すると正確に理解しておく必要があります。

  • コンパイル時
    • javacコマンドの引数には「ソースファイル名」を指定する。
  • 実行時
    • javaコマンドの引数には「完全修飾クラス名」を指定する。
        • 「クラスファイル名」を指定する。
        • 「クラスファイルの拡張子を除いた名称部分」を指定する。

この例ではデフォルトパッケージを使用しているため、完全修飾クラス名と、拡張子を除いたクラスファイル名との違いが分かりにくいですが、パッケージを使用してクラスの定義を行った時に、この差が明確となり、重要性を増します。

パッケージが宣言されたクラスのプログラム実行について詳細はこちらです。

javaコマンド実行時のエラー例

ここまでの手順を踏まえ、敢えて間違った引数を指定してエラー出力を確認することで、javaコマンドによる実行の理解がより深まります。ここでは次の3パターンを試してみます。

  • $ java Main:クラスファイル未作成の状態でクラス名を指定
  • $ java Main.java:ソースファイル名を指定
  • $ java Main.class:クラスファイル名を指定

「$ java Main」未作成の状態でクラス名を指定

1つ目の手順であるソースファイルのコンパイルを行わずにjavaコマンドを実行してみます。引数にはクラス名(≒拡張子を除くクラスファイル名)を指定しており、構文自体は正しいものの、クラスファイルが存在しないため、指定されたクラスを参照することができず、次のようにエラーとなります。

$ java Main
エラー: メイン・クラスMainを検出およびロードできませんでした
原因: java.lang.ClassNotFoundException: Main

「$ java Main.java」ソースファイル名を指定

他の二つと異なり、このパターンはエラーとなる想定にも関わらず、正常に実行できてしまいます。

# ソースファイル名を指定(クラスファイル未作成でも実行できる)
$ java Main.java
Hello World

これは、javaコマンドの ソース・ファイル・モードを使用したソース・コード・プログラムの起動 が適用されているためです。ただしこれはあくまで、初学者によるプログラム実行や開発初期段階の試行錯誤などを想定した機能であり、大規模な開発や本番環境で動作するプログラムでは変わらず、コンパイルを行いクラスファイルを作成する必要があります。

「$ java Main.class」クラスファイル名を指定

引数にクラス名ではなく、拡張子を含むクラスファイル名を指定した場合も、同じようなエラーが出力されます。これは次のような理由からです。

本来javaコマンドの引数には完全修飾クラス名を指定しますが、これは . 区切りでパッケージ名と連結した物となります。例えば、com.example パッケージの Main クラスを指定する場合、実行コマンドは、$ java com.example.Main となります。

その上で改めて、誤ってクラスファイル名を指定してしまった場合のコマンドを見てみると、$ java Main.class となっており、従ってこれは、Main パッケージの class クラスと解釈しようとされることが分かります。そして当然、コンパイルされたクラスファイルに、Main パッケージの class クラスのような定義は存在しないため、以下のようにエラーが出力されることになります。

# コンパイル
$ javac Main.java

# クラスファイル名を指定
$ java Main.class
エラー: メイン・クラスMain.classを検出およびロードできませんでした
原因: java.lang.ClassNotFoundException: Main.class

javacコマンドのオプション

オプションを指定しない場合、javacコマンドは対象のソースファイルと同じ場所にクラスファイルを作成します。しかし、コーディングに使用するソースファイルと、人間が読むことはなく実行時にのみ使用するクラスファイルは、それぞれを格納するディレクトリを分けて管理した方が便利です。そこで、-dオプション を使用すると、次の例のようにクラスファイルの生成先ディレクトリを指定することができます。

1.以下のディレクトリ構成で Main.java が配置されている。

workspace
└ src
   └ com
      └ example
         └ Main.java

2.-d オプションを使用してコンパイルを行う。

# カレントディレクトリは src
$ cd
C:\Users\xxx\workspace\src

# src と同じ階層の bin ディレクトリを -d オプションに指定してコンパイル
$ javac -d ..\bin com\example\Main.java

3.指定したディレクトリ以下も同じ構成でクラスファイルが生成される。

workspace
├ bin
│ └ com
│    └ example
│       └ Main.class
└ src
   └ com
      └ example
         └ Main.java

これは次に示すように、Eclipseでコンパイルを行った時に、binディレクトリにクラスファイルが作成されるのと同様の振る舞いです。

Eclipseの場合

基本的なJava実行の3ステップをコマンドで説明してきましたが、実際に開発を行う場合はEclipse等のIDEを使用することも少なくありません。

例えばjavapコマンドを使って クラスファイルのバージョン を確認したい時、Eclipseによって作成されたクラスファイルがどこに格納されているのかが分からなければ、確認のしようがありません。

このように、IDEによってこれらコンパイル等の操作が自動的に行われている場合、各操作がどのように対応しているかを理解しておくと、柔軟なトラブルシューティングが可能となります。

Eclipseによるコンパイルと、クラスファイルの格納についての詳細はこちらです。