静的変数(static variable)・静的メソッド(static method)とは、特定のオブジェクトにではなく、クラスに属するメンバ変数やメソッドのことです。 そのため、静的変数のとこをクラス変数とも呼びます。 (クラス変数という呼び名の方が意味合い的には正しいのですが、 C言語から派生したというC#の歴史的な背景のため、静的変数という呼び方をします。) それに対し、通常のメンバ変数のことをインスタンス変数と呼びます。
クラスのメンバ変数やメソッドを定義する際に、staticキーワードを付けることで、
その変数は静的メンバ変数・静的メソッドになります。
static 型名 変数名
静的変数・静的メソッドはクラスごとに唯一つの実体を持ち、すべてのオブジェクトの間で共有されます。
例として、人間について考えてましょう。
この場合、特定のオブジェクトとは個人個人のこと、
クラスとは人間という種別そのもののことになるわけですが、
名前や年齢などは各個人ごとに異なりますが、
手足の本数などはすべての人間で共通のものです。
したがって、人間をあらわすPersonというクラスを作成した場合、
name(名前)やage(年齢)といったメンバ変数を作りたい場合はインスタンス変数に、numberOfArms(腕の数)やnumberOfLegs(足の数)といったメンバ変数を作りたい場合は静的変数にすべきです。
(実際には人間の腕の本数などの普遍な値は定数(const)として定義すべきですが、
ここでは説明のためということでご容赦を。
定数の定義については後ほど説明します。)
class Person { public string name; // 名前。個体ごとに違うので、インスタンス変数に。 public int age; // 年齢。同上、インスタンス変数に。 public static int numberOfArms; // 腕の本数。人間に共通なので、静的変数に。 public static int numberOfLegs; // 足の本数。同上、静的変数。 }
静的変数はクラスに属する値なので、値を参照するには以下のようにします。
Person p = new Person() p.name = "野上冴子"; // インスタンス変数は [インスタンス名.変数名] で参照する。 p.age = 40; Person.numberOfArms = 2; // 静的変数は [クラス名.変数名] で参照する。 Person.numberOfLegs = 2;
また、静的変数・静的メソッドは、数学関数や数学定数などのインスタンスを持つ必要のない関数を定義する場合にも使います。 ( 「関数」 で説明した内容は、 実際には(C# 用語的には)関数ではなく、静的メソッドです。)
using System; class Math { // sin x を求める関数。 static double Sin(double x) { double xx = -x * x; double fact = 1; double sin = x; for(int i=0; i<100; ++i) { fact *= i; ++i; fact *= i; ++i; x *= xx; sin += x / fact; } return sin; } } class StaticSample { static void Main() { Console.Write(Math.Sin(1)); } }
標準ライブラリの Math.Sin や Console.Write などは静的メソッドです。
静的変数の初期化には、通常のコンストラクタではなく、静的コンストラクタ(static constructor)というものを使います。
静的コンストラクタの定義の仕方は、コンストラクタの前に static キーワードを付ける以外は通常のコンストラクタの定義の仕方と同じです。
例えば、先ほどの Person クラスを例に挙げると以下のようになります。
class Person { string name; // 名前。インスタンス変数。 int age; // 年齢。インスタンス変数。 static int numberOfArms; // 腕の本数。静的変数。 static int numberOfLegs; // 足の本数。静的変数。 // 通常のコンストラクタ public Person(string name, int age) { this.name = name; this.age = age; } // 静的コンストラクタ static Person() { Person.numberOfArms = 2; Person.numberOfLegs = 2; } }
通常のコンストラクタが新しいオブジェクトが生成されるたびに呼び出されるのに対して、 静的コンストラクタはプログラムの初めに1度だけ呼び出されます。
using System; // 1台ごとに固有のIDが振られるような何らかの製品。 class Product { static int id_generator; int id; static Product() { // 最初に1度だけ呼ばれ、id_generator を 0 に初期化。 id_generator = 0; } public Product() { // 新しい製品が製造されるたびに新しい id を振る。 id = id_generator; id_generator++; } /// <summary> /// その製品のIDを取得する。 /// </summary> public int ID { get{return id;} } } class StaticSample { static void Main() { for(int i=0; i<10; i++) { Product p = new Product(); Console.Write("ID: {0}\n", p.ID); } } }
ID: 0 ID: 1 ID: 2 ID: 3 ID: 4 ID: 5 ID: 6 ID: 7 ID: 8 ID: 9
Ver. 2.0
標準ライブラリ中の Math クラスのように、
静的なメンバしか持たないクラスがあります。
Math クラスに限らず、
static メンバのみを持ち、インスタンスの作成が不可能なクラスを作りたいことがしばしばあります。
C# 1.0 では、private なコンストラクタを持つ sealed クラスとしてこのようなクラスを作成していました。 このような方法で、「インスタンスが作成不可能」という制約は満たすことが出来ますが、 非 static なメンバを定義することができてしまうという問題がありました。 (決してアクセスすることの出来ない無駄なメンバになってしまいます。)
それに対して、C# 2.0 では、
クラス定義時に static をつけることで、
静的メンバしか定義できないクラスを作ることが出来ます。
このようなクラスを静的クラス(static class)と呼びます。
static class Math { // double x; というような、非 static な変数・メソッドは定義できない。 // sin x を求める関数。 static double Sin(double x) { double xx = -x * x; double fact = 1; double sin = x; for(int i=0; i<100; ++i) { fact *= i; ++i; fact *= i; ++i; x *= xx; sin += x / fact; } return sin; } }