Javaは「Write Once, Run Anywhere(1度書けばどこでも動く)」という思想のもと誕生したプログラミング言語です。その中核にはJava仮想マシン(JVM)が存在し、コンパイルされたバイトコードをどのOS上でも同じように実行する仕組みが備わっています。(参考 JDK/JRE/JVMの仕組みを1から解説)
このページでは、Javaの基本コマンドであるjavac
・java
・jar
の使い方を1からわかりやすく解説しつつ、Java 9で導入されたモジュールシステムやJava 11のソースファイルモードにも触れていきます。

さらに、クラスローダ・JITコンパイラ・GCなど、JVMの裏側にある奥深い仕組みにも言及しながら、読んでいて「Javaって実は面白い!」と思える記事にしていますので、是非最後までご覧ください。
Javaプログラムの基本フロー:コンパイルと実行
ソースコードの準備とコンパイル(javac)

Javaのプログラムはソースコード(.javaファイル)をコンパイルしてバイトコード(.classファイル)に変換する作業が必要です。たとえば、HelloWorld.javaに下記のようなクラスを定義します。
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } }
これをコンパイルするには、次のコマンドを実行します。
javac HelloWorld.java
同じフォルダ内にHelloWorld.class
が生成されます。これがバイトコードです。
裏側の仕組み
実行(java)
生成されたバイトコードを実行する際には、拡張子を付けずにクラス名を指定します。
java HelloWorld
これで「Hello, World!」と表示されれば成功です。
裏側の仕組み
Javaコマンドの3つの実行形態 + ソースファイルモード
Javaプログラムをjava
コマンドで実行する方法は、大きく3つ存在します。さらに、Java 11からはソースファイルモードというシンプルな実行形態も加わりました。
- mainメソッドを持つクラスファイル
- jarファイル内のメインクラス
- モジュールに含まれるメインクラス
- (Java 11~)ソースファイルモード
以下では、これらの違いや使い分けを確認していきます。
mainメソッドを持つクラスファイル
もっともシンプルで伝統的な実行形態です。すでに紹介したHelloWorldのように、main(String[] args)
を持つクラスをjavac
でコンパイル後、java クラス名
で起動する方法です。
- メリット: 設定が不要で手軽
- デメリット: 配布やライブラリ管理の段階になると、クラスファイルをまとめる必要が出てくる
jarファイル内のメインクラス
複数のクラスファイルやリソースをまとめたアーカイブファイル(.jar
形式)を生成し、Main-Class
を指定することで、java -jar
コマンドで実行可能にできます。
1 manifest.txtなどでメインクラスを指定 Main-Class: com.example.app.HelloWorld 2 jarコマンドでアーカイブを作成 jar cfm HelloWorld.jar manifest.txt com/example/app/*.class 3 実行 java -jar HelloWorld.jar
これにより、配布やバージョン管理が容易になり、システム全体の保守性が向上します。
モジュールに含まれるメインクラス(Java 9~)
Java 9で導入されたモジュールシステム(Project Jigsaw)は、大規模化したJavaアプリケーションにおけるパッケージ管理をより厳密に行う仕組みです。
module-info.java
でモジュール名やエクスポートするパッケージ、依存モジュールなどを宣言します。- 実行時はモジュールパスとメインモジュール・メインクラスを指定します。
java --module-path mods -m com.example.app/com.example.app.HelloWorld
-module-path
でモジュールを配置したディレクトリを指定-m
オプションで「モジュール名/メインクラス」を指定
モジュール同士の依存関係やアクセス制御を明確化し、ライブラリの衝突などを防ぎやすくなるのが大きな利点です。
3.4 Java 11のソースファイルモード
Java 11からは、単一のソースファイルであればコンパイルを明示せずに直接実行できるようになりました。
java HelloWorld.java
これだけでコンパイルと実行を一括で行います。スクリプト感覚で試験的なコードを書くときや、学習用途にはとても便利です。
: 大規模開発や複数クラスが絡む場合は、従来どおりコンパイル→実行またはIDEのプロジェクト構成が一般的です。あくまでも“単体ファイル”に限り便利な機能です。
jarコマンドの応用:アプリケーションのパッケージング
jarファイルの基本
jar
はZIP形式をベースにしたアーカイブで、クラスファイルやリソースをひとまとめにできます。
- 配布が容易になり、classpathにjarファイルを追加するだけでアプリケーションが動作するようにできます。
META-INF/MANIFEST.MF
にメインクラスやクラスパス情報を記述することで、java -jar
形式の実行ファイルを構築可能です。
実行可能jarとマニフェストファイル
たとえば以下のように、メインクラスを指定したmanifest.txt
を準備します。
Main-Class: com.example.app.HelloWorld
このファイルを用いてjarを作成すると、
jar cfm HelloWorld.jar manifest.txt com/example/app/*.class
すると、
java -jar HelloWorld.jar
でメインメソッドが呼び出され、アプリが起動します。
応用設定:クラスパスとJVMオプション
クラスパス(classpath)の指定
外部ライブラリを使う場合など、Javaがクラスファイルやライブラリを探しに行くパスを指定する必要があります。
javac -cp ./libs/*:. MyApp.java java -cp ./libs/*:. MyApp
.
は現在のディレクトリ:
はパス区切り文字(Windowsでは;
)./libs/*
でlibsフォルダ内のJARすべてを指定
JVM起動オプション(メモリ・デバッグ)
-Xms
-Xmx
: ヒープメモリの初期サイズ・最大サイズを指定(例:-Xms512m -Xmx1024m
)- リモートデバッグ:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 MyApp
指定ポートにデバッガを接続すればブレークポイントを張ってステップ実行が可能です。
Javaの裏側の仕組み
クラスローダ
Javaではクラスローダが複数階層になっており、標準ライブラリを読み込むブートストラップクラスローダ、ユーザのクラスパスを参照するシステムクラスローダなどが段階的にクラスを探します。
- パッケージ名に対応するディレクトリ構造を辿って
.class
ファイルをロード - モジュールシステム利用時はモジュールパスを優先的に参照
JITコンパイラ
JVMは実行時にバイトコードをインタプリタで実行するだけでなく、JITコンパイラによって頻繁に呼ばれるメソッドをネイティブコードに変換します。
- これにより、Javaアプリは起動直後こそ遅めでも、使い込むうちに高速化が期待できます。
ガーベジコレクション(GC)
メモリ管理を自動化するJavaの大きな特徴です。
- ヒープ内の不要オブジェクトをGCが検知し、自動的にメモリを再利用
- GCアルゴリズム(Serial GC, Parallel GC, G1 GC, ZGCなど)をアプリケーション特性に合わせて選択可能
- メモリリークの心配は軽減される一方、開発者がGCタイミングを完全に制御することは難しい