ソースファイル構成とmainを理解する

Javaのソースファイルにはクラス本体だけでなく、所属先を表すpackageや型名を短く書くimportもあります。ファイルの場所、クラスの完全修飾名、起動時の検索ルートを一つの例で結び付け、mainの宣言と引数の結果まで確認します。Java SE 17を前提とします。

この単元で学ぶこと

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

本文解説

ソースファイルの構成 通常のソースファイルは、省略可能なpackage宣言、import宣言、型の宣言の順に書きます。packageは型の所属する名前空間です。package school; class Main {}なら完全修飾名はschool.Mainです。ファイル内のコメントや空行はこの宣言順序を変えるものではありません。

importの役割 import java.util.List;と書くと、ソース内でjava.util.ListをListと短く書けます。クラスの内容をソースへコピーする機能ではありません。java.langの公開型は通常明示importなしで使えるため、StringやSystemを毎回importする必要はありません。

ワイルドカードと名前の衝突 import java.util.*;はjava.util内の型を単純名で利用するためのものです。java.util.concurrentの型まで対象にはしません。またjava.util.*とjava.sql.*の両方をimportしてDateとだけ書くと、両方にDateがあるため曖昧になります。完全修飾名や単一型importで意図を明確にします。

保存する例 Main.javaへ次を保存します。 package school; public class Main { public static void main(String[] args) { System.out.println(args.length); if (args.length > 0) { System.out.println(args[0]); } } } publicなトップレベルクラスの名前とファイル名を対応させます。mainはString配列で起動時の引数を受け取ります。

コンパイルと検索ルート javac -d out Main.javaは出力ルートをoutとし、packageに合わせてout/school/Main.classを生成します。起動はjava -cp out school.Mainです。-cpに指定するのはschoolディレクトリそのものではなく、その一つ上のoutです。javaは完全修飾名を使って検索ルートの下を探します。

引数の出力 java -cp out school.Main red blueなら、args.lengthは2でargs[0]はredなので、2、redの順に二行出力します。java -cp out school.Mainだけなら0の一行です。ifで長さを確かめるため、存在しない要素0を読まずに終わります。クラス名や-cpの引数はmainへ渡す文字列配列に含まれません。

mainとして使える宣言 通常の起動入口はpublic static void main(String[] args)です。public static void main(String... args)も可能で、可変長引数はメソッド内部では配列として扱われます。引数名はargs以外でも構いません。public static int main(String[] args)は通常のメソッドとしては宣言できますが、launcherが要求する起動入口ではありません。

オーバーロードとの違い public static void main(int x)と宣言しても、通常のmain(String[])の代わりにはなりません。両方あるときはlauncherがString[]の入口を選びます。またString[]版とString...版は同じ引数型になるため、同じクラスに両方を別メソッドとして宣言できません。

検証と切り分け 新しい作業ディレクトリでソースを保存し、javacの終了成功とout/school/Main.classの生成を確認してから起動します。クラスが見つからなければ、-cpのルートとschool.Mainの綴りを確認します。mainが見つからないときは戻り値・引数型・public・staticを確認します。変数の配列範囲外例外は起動後の処理の問題なので、クラス探索の失敗と分けます。

図解

パッケージ名と検索場所
ディレクトリのルートと、Javaの型の名前を別々に指定する。

重要ポイント

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

間違えやすい点

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

用語解説

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

関連教材

参考資料

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

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