静的メンバ
静的メンバとstatic
クラスにはフィールドとメソッドをつけることができることがわかりました。それらは、インスタンスを生成することにより利用できましたが、インスタンスを生成しなくても利用できるものもあります。それを、静的メンバと呼びます。
静的メンバを定義するためには、先頭に、static(スタティック)修飾子をつけるだけで簡単に定義できます。しかし、呼び出し方や利用方法には様々な制約があります。
サンプルプログラム
では実際に、静的メンバのサンプルを入力して、試してみましょう。以下のプログラムを入力・実行してみてください。
SampleClassEx01.javapackage exday1; // 静的メンバもつクラス public class SampleClassEx01 { private int value = 0; // インスタンスフィールド private static int num = 0; // 静的フィールド // コンストラクタ① 引数あり public SampleClassEx01(int value){ // 引数をインスタンスフィールドに代入 this.value = value; // 静的メンバのインクリメント num++; } // コンストラクタ② 引数なし public SampleClassEx01(){ this(100); // 引数つきコンストラクタを呼び出す } // インスタンスの数を取得 public static int getNumberOfInstance(){ return num; } // インスタンスフィールドを取得 public int getValue(){ return this.value; } }
package exday1; public class SampleEx101 { public static void main(String[] args) { SampleClassEx01 s1,s2; // インスタンスの数を表示 System.out.println("インスタンス数:"+SampleClassEx01.getNumberOfInstance()); // インスタンスを生成する s1 = new SampleClassEx01(50); // コンストラクタ①を呼び出す s2 = new SampleClassEx01(); // コンストラクタ②を呼び出す // 値を取得して表示する System.out.println(s1.getValue()); System.out.println(s2.getValue()); // インスタンスの数を表示 System.out.println("インスタンス数:"+SampleClassEx01.getNumberOfInstance()); } }
50
100
インスタンス数:2
プログラムの仕組み
static修飾子
SampleClassEx01クラスのフィールドnumおよび、メソッドgetNumberOfInstance()には、先頭に、staticという修飾子がついています。静的メンバは、必ず先頭に、この修飾子をつけます。
このようなメンバは、クラスフィールド、およびクラスメソッドと呼びます。これに対し、インスタンスを生成しなくては使用できないフィールドおよびメソッドは、インスタンスフィールド及びインスタンスメソッドと呼びます。
インスタンスメソッドおよびフィールドへのアクセスには、インスタンス名の後にピリオドをつけて、フィールド名およびメソッド名をつけましたが、それに対し、クラスフィールドおよびクラスメソッドの場合は、先頭にクラス名をつけます。
クラスメソッドおよびクラスフィールドへアクセス(クラス名).(フィールド名); ← 静的フィールドへのアクセス
SampleEx101の8行目および16行目で、クラスメソッドを呼び出していますが、その際、先頭には、クラス名である。SampleClassEx01がついています。
コンストラクタのオーバーロード
ところで、クラスSampleClassEx01には、コンストラクタが複数あります。コンストラクタは、メソッドの一種であることから、オーバーロード、つまり複数のコンストラクタを定義することが可能です。SampleClassEx01.javaの8行目に定義されているのが、15行目に定義されているのが、引数なしのコンストラクタです。
インスタンスの生成方法と対応するコンストラクタs1 = new SampleClassEx01(50); | → | SampleClassEx01(int value) |
s2 = new SampleClassEx01(); | → | SampleClassEx01() |
インスタンスを生成する際、引数を与えれば引数付きのコンストラクタが、与えなければ、引数なしのコンストラクタが呼び出されます。
コンストラクタのthis
ところで、SampleClassEx01.javaの16行目にある、thisは何を意味すするのでしょうか?このように、thisのあとに()をつけて、なかに引数をつけると、コンストラクタから、対応する引数をとるコンストラクタを呼び出すことが可能です。
ここでは、引数として100という値が与えられていますから、引数つきのコンストラクタに、100という値を与えて呼び出したのと同じ効果になります。そのため、s2のフィールドvalueに、値100が設定されます(図1-1.)。
図1-1.thisにより、引数つきコンストラクタを呼び出す。
main()メソッド
今まで特に詳しく説明することがなかった、main()メソッドは、実は、その形からわかる通り、静的メソッドの一つだったのです。クラスに、このmain()メソッドが付いていると、プログラムはそこから実行されます。引数のString型の配列argsは、コンソールから呼び出されるときに追加される文字列です。
ここでは詳細は省略しますが、Javaでは、この型をつけることにより、実行時にこの処理を呼び出すことができるのです。
ガーベージコレクタ
サンプルプログラム
続いて、ガーベージコレクタという概念について説明します。以下のプログラムを実行してみてください。
SampleEx102.javapackage exday1; public class SampleEx102 { public SampleEx102(){ System.out.println("コンストラクタ"); } public void foo(){ System.out.println("インスタンスメソッド"); } public static void bar(){ System.out.println("静的メソッド"); } public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ SampleEx102 i = new SampleEx102(); i.foo(); // 様々な静的メソッドの呼び出し i.bar(); // インスタンスからも、静的メソッドを呼べる SampleEx102.bar(); // クラス名からの呼び出し bar(); // 同じクラス内なら、クラス名無しでも呼び出せる。 // ガーベージコレクタの呼び出し System.gc(); } }
インスタンスメソッド
静的メソッド
静的メソッド
静的メソッド
自分自身のメソッドの呼び出し
15行目のしょりをみてください。main()メソッドの中で、自分自身のメソッドを生成しています。不思議な感じがしますが、クラスメソッドのなかで、同一クラスのインスタンスを生成することも可能で、しばしばプログラミングの高度なテクニックで応用されることがあります。
このクラスSampleEx102には、コンストラクタの他に、2つのメソッドが定義されています。一つがインスタンスメソッドのfoo()、そしてもう一つがクラスメソッドのbar()です。インスタンスメソッドは、あくまでもインスタンスをnewしなくてはならないことは、自分自身のクラスを呼び出す場合も変わりはありません。
クラスメソッドの呼び出し方
このサンプルでは、18行目から20行目で複数の静的フィールドの呼び出し方法が記述されています。
クラスメソッドの呼び出し方SampleEx102.bar(); ← クラス名から呼び出す方法
bar(); ← クラス名を省略する呼び出し方
すでに説明したとおり、通常、クラスメソッドの呼び出し方は、クラス名の後に.をつけて呼び出す方法が推奨されます。しかし、それ以外にも、インスタンス名の後にクラスメソッドをつけて呼び出すことも可能ではありません。ただし、この方法は推奨されておらず、以下のような警告が発せられます。
クラスメソッドを、インスタンスから呼び出した際に発せられる警告警告とは、エラーではなく、プログラム自体は実行できますが、プログラミングの方法としてあまり推奨されないという意味です。プログラミングをする際には、原則的にこの警告が発せられないようなコードを書かないように心掛けましょう。
では、一体どこに誤りがあるのでしょうか?コンパイラーの発するエラーメッセージに従い、6行目を見ると、printllとなっています。これは本来、printlnとすべきところを、誤って記述したものです。 そこで、ここを正しい記述に直してみましょう。
また、20行目を見てもわかるとおり、同一クラス内から別のメソッドを呼び出す場合、クラス名を省略することが可能です。
ガーベージコレクタ
最後に、22行目の処理を見てください。この処理は、ガーベージコレクタの起動を促す処理です。
ガーベージコレクタの起動を促すそもそも、ガーベージコレクタとは何でしょう?ガーベージとは、英語でゴミを意味します。つまり、「ゴミ集め」という意味です。
では、そのゴミとはなんでしょうか?Javaでは、プログラム内でnewを用いてインスタンスを生成すると、そのインスタンスは、メモリの中に蓄積されます。このインスタンスは、必要がなくなれば、メモリの中から消去されます。そうしなければ、メモリが圧迫されて、プログラムがストップしてしまう可能性があります。この処理を行うのが、ガーベージコレクタの役割です。
そして、22行目の処理を行うと、ガーベージコレクタの起動を促すことが可能なのです。ここでポイントになるのは、あくまでも「促す」という点にあることです。つまり、この処理を行ったからと言って、必ずガーベージコレクタが起動されるわけではないということです。
基本的にガーベージコレクタは、自分自身の判断で呼び出されるため、どのタイミングで呼び出されるかはわかりません。しかし、この処理を行うことにより、「適切なタイミングで」呼びだされることが期待されるのです。(図1-2.参照)
図1-2.ガーベージコレクタ
練習問題 : 問題1.