3-4: メンバーの static宣言の意味


・ クラスとオブジェクトの区別を強調するために、 説明の中で「クラス=設計図、オブジェクト=製品」という図式を用いました。 しかし実際のコンピュータの内部では、もう少し境界が微妙な状況が生じます。 現実の工業製品の場合と異なる点は、 プログラムの実行中にはクラスの情報(設計図)も 個々のオブジェクトの情報(製品)も、 どちらもコンピュータのメモリー上に存在しているということです。 両者を物理的に区別する違いは特にありません。 このため、各オブジェクトの情報はクラスの側にあっても不便はありません。 実際、クラスの中に定義された手続きや 全てのオブジェクトよって共有されるデータなどは、クラスの側に存在します。 言ってみれば「製品の一部分」を構成する一方で、 その実体は「設計図の中に存在する」わけです。 現実の工業製品では製品が製造されなければ話になりません。 しかしプログラムの場合には、 オブジェクトを生成せずにクラスの情報のみを利用するケースもあり得ます。

・ これまで紹介してきたサンプルのプログラムの中で、 しばしば static というキーワードが使用されていました。 この宣言は、オブジェクトの情報がクラスに共通したものであるか、 それとも個々のオブジェクトに固有のものであるかという区別を表しています。 static がフィールドに対して宣言された場合には、 そのフィールドはクラスの すべてのオブジェクトによって共有されるデータとなります。 したがって、 そのメモリーの確保も個々のオブジェクトごとには行われません。 クラスのバイトコードがロードされた段階で、 既にクラスの情報として領域が確保されています。 言い換えると static宣言されたフィールドのデータは、 オブジェクトを生成するまでもなく存在しているわけです。
実際 static宣言されたフィールドは「クラスのフィールド」として アクセスすることが可能です。 先に紹介したサンプルの中で Colorクラスのオブジェクトを生成する例がありました。 実は Colorクラスは、 使用頻度の高い原色の色の情報 13色を staticなフィールドとして用意しています。 それらを利用すれば、 いちいちコンストラクタを呼び出さなくても必要な Colorのオブジェクトを得ること ができます。具体的には次のようにします。


Color.blue;
 

これは new Color( 0, 0, 255 )というコンストラクタを呼び出したのと、 まったく同じ結果を与えてくれます。 Color.blue というように個々のオブジェクトではなく クラス名の後に "." が付いている点に注目してください。

・ メソッドの頭に static宣言が付くのはどのような場合でしょうか?  メソッドの手続きの内容はすべてクラスの情報として保持されています。 その意味ではメソッドは元々 staticな存在とも言えます。 メソッドの場合の static は、 staticでないオブジェクト固有なフィールドを、 そのメソッドが取り扱わないことを意味します。 取り扱うのは staticなフィールドかローカル変数に限るということです。 メソッドの呼び出しが許されるのも他の staticなメソッドに限りられます。 少し厳しい制限のようですが、 これによって staticなメソッドもオブジェクトを生成しなくても利用できることに なります。要するに、次のように覚えておくのが一番わかりやすいでしょう。

・ staticなフィールドは、コンストラクタの定義の中で値の初期化はできません。 (値の変更はできます。) 多数の staticなフィールドがあり、複雑な初期化を行う必要がある場合のため、 名前のない static なブロックを定義することができます。 名前がないので、通常のメソッドのように 別の場所から呼び出すことはできません。 staticなブロックはフィールドの初期化の一連の処理の一部にすぎず、 実行されるのはクラスが JVM(Java仮想マシン)にロードされた直後の1度限りです。 また staticなブロックは複数定義することもできます。 その場合の初期化の処理は単に上から下にプログラムに記述された順に行なわれます。 main()メソッドが呼び出されるのは、これらの初期化が終わったあとになります。


static {

    /* staticなフィールドの複雑な初期化の処理 */
}

一般に staticなメンバーを活用することで、 オブジェクト生成に要する余分なオーバーヘッドを減らしたり、 メモリー資源を節約したりする効果が得られます。
また、必ず staticにしなければならないメソッドもあります。 main() が常に static になっていることに気づいた人は多いでしょう。 main() の呼び出しは JVMによって行われますが、 その時点ではオブジェクトは1個も生成されていません。 したがって必然的に staticにならざるを得ないのです。