ソースファイル構成とmainのコードトレース

パッケージを持つRunnerを実際のコマンドで起動する事例です。コンパイルの出力先、クラスパス、mainの宣言、引数配列を一続きで追います。Java SE 17の通常のclass起動を使い、プレビュー機能やソースファイル起動は使いません。

この単元で学ぶこと

  • package・import・型宣言の順序を説明できる
  • パッケージ付きクラスをコンパイルして起動できる
  • mainの宣言と引数の配列から結果を予測できる

本文解説

例のソース Runner.javaへ次を保存します。 package academy; public class Runner { public static void main(String[] args) { System.out.print(args.length); if (args.length > 1) System.out.print(":" + args[1]); } } この型の完全修飾名はacademy.Runnerです。引数の二番目を出す前に、長さが1より大きいかを調べています。

生成物を対応させる javac -d build Runner.javaを実行するとbuild/academy/Runner.classが生成されます。buildは出力のルートであってpackage名ではありません。ルートをclassesへ変えれば生成物はclasses/academy/Runner.classになり、型の完全修飾名は変わりません。

引数を三通り試す java -cp build academy.Runnerなら0、末尾にnorthを一つ指定すると1、north southを指定すると2:southです。main内でprintを使っているので末尾の改行はありません。引数名argsがvaluesでも型とコードを一貫して直せば同じ結果になります。

引用符を含む起動 java -cp build academy.Runner "north south" westでは、通常のシェルは引用符の中の空白を一つの引数内として扱います。配列は二要素で、出力は2:westです。外側の引用符自体は引数の一部として渡りません。引数の分割はJavaのprintlnが後から行う処理ではありません。

探索エラーを作る java -cp build/academy academy.Runnerはルートが深すぎ、標準的なこの配置ではクラスを見つけられません。java -cp build Runnerもpackageを落としているので正しい起動ではありません。ビルド成功と起動指定の正しさは別に確かめます。

入口を変えたとき String[]をString...へ変えた版は入口として使えますが、同時に両方を宣言すると同じ引数型が重複します。main(int n)だけを残す版はメソッドとしてコンパイルできますが、文字列配列の入口がなく通常起動できません。エラーを「コンパイル段階」か「launcherの入口検出」かに分けます。

importの事例 別の例でimport java.util.*;とimport java.sql.*;を書きDateを単純名で使うと曖昧です。java.util.Dateと完全修飾すれば対象を特定できます。またimport java.util.*;だけではjava.util.concurrent.TimeUnitをTimeUnitと短く書けません。packageの階層とimportの対象を別々に追います。

検証の進め方 元のRunnerを生成して三通りの引数を確認してから、-cp、完全修飾名、mainの引数型を一つずつ変えます。各変更後にコンパイルが必要かを判断し、ソース変更なら再生成します。別の試行の古いclassが混ざらない新しい出力ルートを使うと、期待した版が動いているかを確認しやすくなります。

図解

Runnerの出力先と起動名
引数はクラス名の後ろから渡る。-cpのルートをpackage名に含めない。

重要ポイント

  • package、import、型宣言の順に置く。
  • importは名前解決でありコードのコピーではない。
  • -cpはパッケージ階層のルートを指定する。
  • mainのオーバーロードがすべて起動入口になるわけではない。

間違えやすい点

  • java.util.*にサブパッケージが含まれると思わない。
  • out/schoolをクラスパスのルートにしない。
  • String[]とString...を別の引数型として重複宣言しない。

用語解説

package
型を分類する名前空間。完全修飾名の前半を構成する。
import
型などを短い名前で参照するための宣言。
完全修飾名
パッケージ名を含めた型の名前。例はschool.Main。
クラスパス
クラスを探索するためのルートの一覧。
可変長引数
呼出し時に複数の値を受け取れ、メソッド内では配列として扱う引数。

関連教材

参考資料

教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。

確認問題の出題・採点や学習履歴の保存にはログインが必要です。