はじめに
誤りについては優しく指摘してくださると嬉しいです。
概観
修飾子staticをつけることでクラスに属するようにし、
全てのインスタンスで共有されるようにしたフィールドやメソッドが静的メンバ。
静的メンバはクラスメンバとも言う。
静的メソッド、静的フィールドはそれぞれクラスメソッド、クラスフィールドとも言う。
インスタンス間で共通している変数を作りたいときなんかにstaticで定義する。
オブジェクト指向でない言語で言うところの関数みたいなイメージになった。
具体例
静的フィールド
次のようなクラスにおいて、静的フィールドとしてnumを定義することを考える。
namespace Sample
{
internal class Class
{
// 静的フィールドとしてnumを定義し初期値を0に。
private static int num = 0;
// 通常のフィールド
private int id;
// コンストラクタ
public Class(int id)
{
this.id = id;
num++; // インスタンスが生成される度にnumが1増える
Console.WriteLine("id:{0} オブジェクト数(計):{1}", this.id, num);
}
// 静的メソッド
public static void ShowNumber()
{
Console.WriteLine("オブジェクトの数:{0}", num);
}
}
}
このコードを以下のように実行すると、numがインスタンス間で共有されており、
インスタンス生成の度に1増えているのが分かる。
namespace Sample
{
internal class Program
{
static void Main(string[] args)
{
// インスタンスを格納する配列を宣言
Class[] d = new Class[2];
// インスタンスの数を表示
Class.ShowNumber(); // この時点でオブジェクトは0
for (int i = 0; i < d.Length; i++)
{
d[i] = new Class(i * 10);
Class.ShowNumber();
}
}
}
}
// 出力結果
// オブジェクトの数:0
// id:0 オブジェクト数(計):1
// id:10 オブジェクト数(計):2
また、静的フィールドにアクセスするには、クラス名.フィールド名でアクセスしなければならない。
Console.WriteLine(Class.num);
// 出力
// 2
静的コンストラクタ
静的フィールドを初期化するには、静的コンストラクタを使う。
例えば同じ会社の社員についてのクラスを以下のように定義したとする。
所属している会社は同じはずなので、静的フィールドで設定しており、
その値を静的コンストラクタで初期化している。
class Person
{
int age; // インスタンスフィールド
string gender; // インスタンスフィールド
static string EmployedBy; // 静的フィールド
// 通常のコンストラクタ
public Person(int age, string gender)
{
this.age = age;
this.gender = gender;
}
// 静的コンストラクタ
static Person()
{
Person.Employedby = "A Company";
}
}
静的コンストラクタは、そのクラスの何らかのメンバーに初めてアクセスしたときに1度だけ呼び出される。
静的メソッド
続いて静的メソッドfoo()を以下のように定義して実行する。
namespace Sample2
{
internal class Program
{
// staticなフィールド
private static int snum = 100;
// インスタンスフィールド
public int inum = 200;
// staticなメソッド
public static void foo()
{
Console.WriteLine("staticメソッド");
}
// インスタンスメソッド
public void bar()
{
Console.WriteLine("インスタンスメソッド");
}
static void Main(string[] args) // エントリポイント(Main)はここ
{
// インスタンス生成
Program p = new Program();
// インスタンスフィールドはインスタンスを通してアクセス
Console.WriteLine("pのインスタンスフィールド:inum = {0}", p.inum);
// staticフィールドはProgram.snumのようにクラス名を通じてアクセスする
// 今回は同じクラス内なので、snumだけでもアクセスできる
Console.WriteLine("Programのクラスフィールド:snum = {0}", snum);
foo();
p.bar();
}
}
}
静的メソッドは静的メンバーにしかアクセスできない。
メソッドからインスタンスフィールドにアクセスする必要がなければ、
静的メソッドにしておく方が実行効率の面で良い (らしい)。
また、よく使う計算処理なんかもインスタンスを生成する必要はないので、静的メソッドで作っておくとよい。
静的クラス
標準ライブラリの1つであるMathのように、静的メンバのみをもつ、インスタンス生成が不可能なクラスも定義できる。
具体的にはクラス定義時にstatic classと書くことで定義できるようだが、今のところ書く機会がないので、その時に追記する。
結論
staticをつけることで定義できるのが静的メンバ。
静的メンバはインスタンス化せずにアクセスできるため、共通した処理を書くのに便利。また、インスタンス間で共有されるためカウンタや全てに共通する状態や定数の保持に使うことができる。
参考