今回はクラスのインスタンスについてです。
クラスについての記事にインスタンスというワードが出てきましたが、少しくわしく解説します。
ここはC#つまずきやすいところなので、なるべくわかりやすく説明したいと思います。
インスタンスとは?
クラスについてで「クラスを使えるようにするには、newキーワードを使ってインスタンスを作成します。」と書きました。
クラスはユーザーが作る新しいデータ型です。
クラスの定義はパソコンに「こんなデータ型があります」と教えるためのものです。
実際にクラスを使うためにはパソコンに頼んでクラスを使える状態にしてもらいます。
頼まれたパソコンはメモリー上にクラスのフィールドを格納するための場所を作ったり、
メソッドがどんな引数が必要でどういう処理をするのかという情報を作成します。
作成された情報がそのクラスのインスタンスと呼ばれるものです。
インスタンスが作られるとパソコンはここに作ったという場所情報(アドレスと言ったりする)を返してきます。これを変数に入れるとクラスが使える状態になります。
//クラスの定義
class Sample
{
public int X;
public void Method() { }
}
class Program
{
public static void Main()
{
//クラスのインスタンスを作成
Sample a = new Sample();
}
}
こんなイメージ、
変数aはクラスのインスタンスを差し示しています。
この状態の変数aをクラスのオブジェクトと呼んだりします。
こんなイメージ、
そもそもなんでこんなことが必要か?
値型と呼ばれるintやboolなどは使用するバイト数が決まっているので、変数の宣言時にメモリー上に必要な分だけ領域が確保されます。
クラスは変数やメソッドを自由に組み合わせて使われるので、どのくらいの領域(バイト数)が必要なのかわかりません。なので「こんなデータとメソッドの組み合わせです」という情報(クラスの定義)をもとに領域を確保する必要があります。
こちらは、変数にインスタンスの場所が格納されるので参照型と呼ばれます。
というわけで、
参照型に分類される型はサイズがあらかじめ決まっていないのでインスタンスを作成する必要があります。参照型はクラスの他に配列やインターフェースなどがあります。
クラスインスタンスのメンバーへのアクセス
「変数a.フィールド名」とすると、クラスインスタンスのフィールドを指し示します。
Sample a = new Sample();
a.X = 10; //クラスのフィールドXに10を代入
「変数a.メソッド名」 とするとクラスインスタンスのメソッドを指し示します。
Sample a = new Sample();
a.Method(); //クラスのメソッドを実行
それぞれのインスタンス
インスタンスは new を実行するごとに新しく作成されます。
クラスのインスタンスを3つ作成してみます。
class Sample
{
public int X;
public void Method() { }
}
class Program
{
public static void Main()
{
Sample a = new Sample();
Sample b = new Sample();
Sample c = new Sample();
}
}
変数a、変数b、変数cはそれぞれ別のインスタンスを差し示しています。
フィールドに値を設定してみる
2つ変数がそれぞれ別のインスタンスを指している場合と、
2つ変数が同じインスタンスを指している場合、違う動きをするため注意が必要です。
それぞれのインスタンスを指している場合
フィールドにint型の変数X、Yを持っているクラスを定義し、
2つのインタンスを作成し、それぞれのフィールドに値を設定してみます。
class Sample
{
public int X;
public int Y;
}
class Program
{
public static void Main()
{
Sample a = new Sample();
Sample b = new Sample();
a.X = 10;
a.Y = 20;
b.X = 30;
b.Y = 40;
System.Console.WriteLine($"a.X = {a.X}, a.Y = {a.Y}");
System.Console.WriteLine($"b.X = {b.X}, b.Y = {b.Y}");
}
}
結果はこんな感じです。
a.X = 10, a.Y = 20
b.X = 30, b.Y = 40
11、12行目でそれぞれのインスタンスが作成され、変数a、bがそれらを差している状態になります。
14~18行目で、
それぞれが指しているインスタンスのフィールドにアクセスしてそれぞれ値が設定されます。
同じインスタンスを指している場合
フィールドにint型の変数X、Yを持っているクラスを定義し、
2つの変数が同じインスタンスを指している状態でフィールドの値を設定してみます。
class Sample
{
public int X;
public int Y;
}
class Program
{
public static void Main()
{
Sample a = new Sample();
Sample b = a; // 変数aの参照情報を変数bに代入
a.X = 10;
a.Y = 20;
b.X = 30;
b.Y = 40;
System.Console.WriteLine($"a.X = {a.X}, a.Y = {a.Y}");
System.Console.WriteLine($"b.X = {b.X}, b.Y = {b.Y}");
}
}
結果はこんな感じです。
a.X = 30, a.Y = 40
b.X = 30, b.Y = 40
変数a、変数bのフィールドに同じ値が設定されています。
どういうことかというと、
11行目でSampleクラスのインスタンスを作成しています。
12行目で11行目で作成したインスタンスの参照情報をコピーしています。
こんな状態になります。
14、15行目でインスタンスのフィールドXに10、Yに20を設定しています。
17、18行目でインスタンスのフィールドXに30、Yに40を設定しています。
変数bは変数aと同じインスタンスを指しているのでフィールドの値が上書きされます。
インスタンスの寿命
基本的に、作成されたインスタンスはどこからも参照がなくなるとC#が自動で破棄(メモリーに確保した場所を解放して他のプログラムが使えるようにする)してくれます(ガベージコレクションという)。
「どこからも参照がなくなる」のはこんなとき、
- スコープが外れたとき(くわしくはそのうち)
- 他の値、nullが代入されて、どの変数にもそのインスタンスの参照情報が入っていないとき
- プログラムが終了したとき
また、手動で破棄が必要なものはIDisposableインターフェースを実装しているのでusingを使って変数を宣言するようにします。くわしくはそのうちまとめる予定です。
C# 記事まとめページに戻る(他のサンプルコードもこちら)
コメント