PR

Javaコマンドの基本を3分でわかりやすく(実は奥が深い?)

Java

Javaは「Write Once, Run Anywhere(1度書けばどこでも動く)」という思想のもと誕生したプログラミング言語です。その中核にはJava仮想マシン(JVM)が存在し、コンパイルされたバイトコードをどのOS上でも同じように実行する仕組みが備わっています。(参考 JDK/JRE/JVMの仕組みを1から解説

このページでは、Javaの基本コマンドであるjavacjavajarの使い方を1からわかりやすく解説しつつ、Java 9で導入されたモジュールシステムやJava 11のソースファイルモードにも触れていきます。

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

スポンサーリンク

Javaプログラムの基本フロー:コンパイルと実行

ソースコードの準備とコンパイル(javac)

Javac,Javaコンパイラ
図1:Java/コンパイル

Javaのプログラムはソースコード(.javaファイル)をコンパイルしてバイトコード(.classファイル)に変換する作業が必要です。たとえば、HelloWorld.javaに下記のようなクラスを定義します。

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

これをコンパイルするには、次のコマンドを実行します。

javac HelloWorld.java

同じフォルダ内にHelloWorld.classが生成されます。これがバイトコードです。

裏側の仕組み

  • javacはJavaソースを内部的に“抽象構文木”へ変換し、そこからJVMが解釈できる命令セット(バイトコード)へ落とし込みます。
  • .classファイルには定数プールやメソッド情報などが含まれており、実行に必要な情報がコンパクトに格納されます。

実行(java)

生成されたバイトコードを実行する際には、拡張子を付けずにクラス名を指定します。

java HelloWorld

これで「Hello, World!」と表示されれば成功です。

裏側の仕組み

  • javaコマンドで指定されたクラスをJVMが読み込み、まずクラスローダによって.classファイルをロードします。
  • その後、インタプリタがバイトコードを1命令ずつ解釈して実行しますが、高頻度で呼び出されるコードはJITコンパイラによってネイティブコードへ最適化され、高速化します。
  • こうした仕組みにより、「Write Once, Run Anywhere」が実現されています。

Javaコマンドの3つの実行形態 + ソースファイルモード

Javaプログラムをjavaコマンドで実行する方法は、大きく3つ存在します。さらに、Java 11からはソースファイルモードというシンプルな実行形態も加わりました。

  1. mainメソッドを持つクラスファイル
  2. jarファイル内のメインクラス
  3. モジュールに含まれるメインクラス
  4. (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タイミングを完全に制御することは難しい
タイトルとURLをコピーしました