staticメソッドの整理も含めて、これまで触れてこなかった「main()メソッド」について見てみましょう。
main()メソッドのありなし
これまでのサンプルプログラムでは、すべて「~Runner」というクラスのmain()メソッドを実行するものでした。
では、main()を持つクラスとはなんなのでしょう。
なんでもありません。
ただのクラスです。単にmain()メソッドを持っている、というだけです。
また、main()メソッドはどんなクラスにも持たせることができます。要は、実行する際に「どのクラスのmain()メソッドを使うのか」ということです。
/**
* フィールド1つとmain()メソッドを持つクラス。
* このクラスも実行できます。
*/
class HasMain
{
// int型変数のフィールドdataを定義します。
int data;
/**
* main()メソッド。こっちも実行できます。
*/
public static void main( String[] args )
{
// HasMainクラスのインスタンスを作ります。
HasMain ref = new HasMain();
// 数値を入れて出力します。
ref.data = 100;
System.out.println( ref.data );
// 出力結果:
// 100
}
}
/**
* 実行用クラス。このクラスを実行してください。
*/
class HasMainRunner
{
public static void main( String[] args )
{
// HasMainクラスのインスタンスを作ります。
HasMain ref = new HasMain();
// 数値を入れて出力します。
ref.data = 100;
System.out.println( ref.data );
// 出力結果:
// 100
}
}
// HasMainRunner.java /** * フィールド1つとmain()メソッドを持つクラス。 * このクラスも実行できます。 */ class HasMain { // int型変数のフィールドdataを定義します。 int data; /** * main()メソッド。こっちも実行できます。 */ public static void main( String[] args ) { // HasMainクラスのインスタンスを作ります。 HasMain ref = new HasMain(); // 数値を入れて出力します。 ref.data = 100; System.out.println( ref.data ); // 出力結果: // 100 } } /** * 実行用クラス。このクラスを実行してください。 */ class HasMainRunner { public static void main( String[] args ) { // HasMainクラスのインスタンスを作ります。 HasMain ref = new HasMain(); // 数値を入れて出力します。 ref.data = 100; System.out.println( ref.data ); // 出力結果: // 100 } }
HasMainクラスは、普通のフィールドとmain()メソッドを持っています。
このmain()メソッドは、HasMainRunnerクラスのmain()メソッドとまったく同じです。
* フィールド1つとmain()メソッドを持つクラス。
* このクラスも実行できます。
*/
class HasMain
{
// int型変数のフィールドdataを定義します。
int data;
/**
* main()メソッド。こっちも実行できます。
*/
public static void main( String[] args )
{
// HasMainクラスのインスタンスを作ります。
HasMain ref = new HasMain();
// 数値を入れて出力します。
ref.data = 100;
System.out.println( ref.data );
// 出力結果:
// 100
}
}
/** * フィールド1つとmain()メソッドを持つクラス。 * このクラスも実行できます。 */ class HasMain { // int型変数のフィールドdataを定義します。 int data; /** * main()メソッド。こっちも実行できます。 */ public static void main( String[] args ) { // HasMainクラスのインスタンスを作ります。 HasMain ref = new HasMain(); // 数値を入れて出力します。 ref.data = 100; System.out.println( ref.data ); // 出力結果: // 100 } }
コンパイルして、実行する際には、これまで通りHasMainRunnerクラスを実行することもできますし、HasMainクラスを実行することもできます。
まずHasMainRunnerクラスを実行する場合を考えてみましょう。
「java HasMainRunner」と実行すると、javaコマンドは、まずHasMainRunnerクラスの静的領域を作成します。
次に、静的領域の中から「メソッド名が『main』で引数が『String[]』のstaticメソッド」を探します。
見つけたらそれを呼び出します。
呼び出したら、main()メソッドの中でHasMainクラスのインスタンスを作り、dataフィールドに数値を入れて出力する、といういつもの処理を行っています。
では次に、HasMainクラスを実行する場合を考えてみましょう。
「java HasMain」と実行すると、javaコマンドは、まずHasMainクラスの静的領域を作成します。
次に、静的領域の中から「メソッド名が『main』で引数が『String[]』のstaticメソッド」を探します。
見つけたらそれを呼び出します。
呼び出したら、main()メソッドの中でHasMainクラスのインスタンスを作り、dataフィールドに数値を入れて出力する、といういつもの処理を行っています。
つまり、どちらのクラスであっても、実行方法に違いはないわけです。main()メソッドを持つクラスが偉いとかそういうこともありません。
「HasMainクラスのmain()メソッドを実行する」というと、なんだか変な気がするかもしれません。特に、main()メソッド内で「自分自身のインスタンスを作っている」のが不思議に感じるかもしれません。
でも全然変じゃないんです。
main()メソッドは静的領域にあるstaticなメソッドですから、main()メソッドが呼び出された時点ではHasMainクラスのインスタンスはまだ作られていません。静的領域は作られていますが、それはインスタンスとは別ですから。
ここまでが下準備
ここまでが、「オブジェクト指向」を学ぶ上での一番基本的な部分です。
ここからは、「継承」というオブジェクト指向の中でもとても重要な機能について見ていきます。
ここまでの範囲のうち、少なくともクラス、インスタンス、参照の関係がちゃんとイメージできるようになってください。そのイメージさえちゃんとできれば、継承も難しくはないでしょう。