■インスタンス・メソッドと静的メソッドの違い
本連載第1回の最初では、右にあるような図を示し、オブジェクトの正体はメモリ上に割り当てられた1つの領域であることを述べました。この図では、メソッド自体(メソッドの内容を記述した処理コード)もオブジェクトに含まれているように描いていますが、実際にはそのようなことはありません。
これは1つのクラスから複数のオブジェクトが作成された場合を考えるとすぐに分かります。オブジェクトの内部データ(=フィールド)は、プログラムが実行される間にいろいろと書き換えられ、普通はインスタンスごとに違う内容になります。しかし、メソッドの内容は書き換えられることがないので、どのインスタンスでも同じ内容です。つまりメソッドの実体はメモリ上に1つあれば十分です。
次の図は、インスタンス・メソッドと静的メソッドを定義した「クラスA」をコンパイルし、それが実行時にメモリ上にロードされている様子を示しています。各メソッドの実体は、ロードされたクラス部分にあります。また、すでにクラスAの2つのインスタンス「オブジェクト1」と「オブジェクト2」が作成されているものとします。これらはロードされたクラスとは別のメモリ領域部分に割り当てられます。
まず、各オブジェクトに対してインスタンス・メソッドが呼び出される場合を考えてみましょう。このとき実際に実行されるメソッドの実体は、クラス部分にあります。しかしながら、メソッド内でフィールドの値を操作する場合には、各オブジェクトのフィールド部分に格納されているデータにアクセスすることになります。
次に、静的メソッドを呼び出している様子です。静的メソッドの呼び出しは、メモリ上にロードされたクラス内のメソッドを直接呼び出すようなイメージになります(図11の(1))。静的メソッドはクラス内に身を置いているものの、「クラスをインスタンス化してオブジェクトを作成する」という世界とは別次元の存在であると考えると分かりやすいかもしれません。
静的メソッドの呼び出し方と同じ記述方法(クラス名.メソッド名)でインスタンス・メソッドを呼び出そうとしてもコンパイル・エラーとなります(図11の(2))。
また、静的メソッド内からインスタンス・メソッドを直接呼び出そうとしてもコンパイル・エラーになります。よくある間違いは、次のようなプログラムです。
静的メソッドからインスタンス・メソッドを呼び出したいならば、次のようにしてインスタンスを作らなければなりません。
あるいは次のように、instanceMethodメソッドが静的メソッドであればOKです。
このSample1クラスのように、すべてのメソッドが静的メソッドであるプログラムは、まるでC言語のプログラムのようです。C#やVB.NETで記述していても、このような全然オブジェクト指向でないプログラムは書けてしまいます。
また、静的メソッドからはフィールドのデータにアクセスすることはできません*6(図11の(3))。次のようなプログラムはコンパイル・エラーになります。
*6 実はフィールドにもインスタンス・フィールドと静的フィールドがあります。しかし静的フィールドは、あまり用途がないため本連載では割愛しています。本連載で単に「フィールド」と記述した場合には、すべて(privateな)インスタンス・フィールドを意味しています。
これも恐らくは次のようにするべきものでしょう。
先ほども述べたように、オブジェクトは、そのフィールドにインスタンス固有の内部データを格納しています。これは各オブジェクトが状態を持っているといえます。たいていのインスタンス・メソッドは、そのフィールドを操作しながら、あるいはフィールドの値に従って処理を進めていきます。
逆に、インスタンス固有の状態を持たずに処理を進められる場合があります。このような処理は静的メソッドとして記述できます。クラス・ライブラリに収められているクラスには静的メソッドを持つクラスがたくさんありますので、リファレンス・マニュアルを見るときには、どのようなメソッドが静的メソッドとして定義されているかにも注目してみてください。
今回はリファレンス・マニュアルでFormクラスのメンバについて見ましたが、いくつかのプロパティやメソッドには、カッコ書きで「Controlから継承されます」とあったはずです。これはFormクラスが、同じSystem.Windows.Forms名前空間のControlクラスを「継承」しているためです。次回(こそ)は、この「継承」について解説する予定です。
Copyright© Digital Advantage Corp. All Rights Reserved.