p.171(ガベージコレクション)
・プログラムの中で生成されたオブジェクトは、基本的に終了時に破棄される ・言語によっては、プログラムの中で動的に記憶領域を確保したり破棄できるものもある ・しかし、C#などでは、オブジェクトの生成のみが可能で、プログラム側で破棄することはできない ・そこで、C#などでは、オブジェクトを参照する変数を無くすることで、オブジェクトの利用を終了したことを、システムに示すことができる ・システムは定期的な監視により、利用が終了したオブジェクトを破棄する。これをガベージコレクションという ・例:MyClass a = new MyClass(), b = new MyClass(); a = b; //最初にa用に生成したオブジェクトは破棄対象 ・例:MyClass a = new MyClass(), a = null; //a用に生成したオブジェクトは破棄対象 ・この仕組みを理解することで、非常に多くのデータを用いる処理において、使っていないオブジェクトが終了時まで残ってしまうことを 防止できる。
p.171 デストラクタ
・オブジェクトの生成時に呼ばれるコンストラクタとは逆に、オブジェクトの破棄時に呼ばれるのがデストラクタ
・デストラクタはオブジェクトの生成時に中身が空のものが自動生成されて呼び出されるが、プログラマの記述も可能
・ただし、直接呼び出したり、動作タイミングを制御することはできず、システム任せになる
・よって、主に、後始末に用いると良い
・定義書式: ~クラス名(){…}
・デストラクタはコンストラクタと同様に、戻り値はない(voidの指定も不可)
・しかも、引数も指定できないので、オーバーロードもできない
・プログラムの終了時のように複数のオブジェクトが破棄される時、すべてのデストラクタが確実に実行されるが、その実行順序は不定であり、
プログラムから知ることもできない
アレンジ演習:p.173 destruct01.cs
・変数dt2、dt3を用いずに、3つのオブジェクトを全て変数dt1で扱うとどうなるか確認しよう ⇒ 動作はアレンジ前と変わらない ・タイミングを見るために「Console.ReadLine();」を末尾に入れて、表示を確認後、Enterキーを入力して終了させよう
作成例
//アレンジ演習:p.17 destruct01.cs
using System;
class DestructTest {
int x;
// デストラクタ
~DestructTest() {
Console.WriteLine("デストラクタが呼ばれました");
Console.WriteLine("xは{0}です", x);
}
// 引数付きコンストラクタ
public DestructTest(int n) {
Console.WriteLine("コンストラクタが呼ばれました");
x = n;
Console.WriteLine("xに{0}を代入しました", n);
}
}
class destruct {
public static void Main() {
//コンストラクタが呼ばれ1を持つオブジェクトを生成
DestructTest dt1 = new DestructTest(1);
Console.WriteLine("dt1生成");
//コンストラクタが呼ばれ2を持つオブジェクトを生成、1を持つオブジェクトは破棄対象になる
dt1 = new DestructTest(2); //【変更】
Console.WriteLine("dt2生成");
//コンストラクタが呼ばれ3を持つオブジェクトを生成、2を持つオブジェクトは破棄対象になる
dt1 = new DestructTest(3); //【変更】
Console.WriteLine("dt3生成");
Console.ReadLine(); //【追加】終了待ち
}
}
アレンジ演習:p.173 destruct01.cs
・50,000回の繰返しにして50,000個のオブジェクトを全て変数dt1で扱うとどうなるか確認しよう ⇒ 生成中にメモリ不足が発生するとみなされて、生成と並行して破棄が行われる(可能性が高い) ⇒ よって、コンストラクタのメッセージとデストラクタのメッセージが混在する(可能性が高い)
作成例
//アレンジ演習:p.17 destruct01.cs
using System;
class DestructTest {
int x;
// デストラクタ
~DestructTest() {
Console.Write("デストラクタが呼ばれました");
Console.WriteLine("xは{0}です", x);
}
// 引数付きコンストラクタ
public DestructTest(int n) {
Console.Write("コンストラクタが呼ばれました");
x = n;
Console.WriteLine("xに{0}を代入しました", n);
}
}
class destruct {
public static void Main() {
DestructTest dt1 = new DestructTest(0);
for(int i = 1; i < 50000; i++) { //【追加】
dt1 = new DestructTest(i); //【変更】
}
Console.ReadLine(); //【追加】終了待ち
}
}
p.174 this
・自分自身を指す参照をthisで得ることができる ・よって、自クラス型の変数を宣言しておいて、thisを代入できる ⇒ p.174 this01.cs ・このこと自体には実用性がないが、下記の応用例において、活用される
p.174 補足:thisの応用例① クラス変数の値を書き換えた結果を返す
・こうすると返された自オブジェクトへの参照をそのまま利用できる
・例:
class Monster {
public int hp, mp;
public Monster hpx(int d) { hp *= d; return this; } //HPをd倍した結果のオブジェクトを返す
public Monster mpx(int d) { mp *= d; return this; } //MPをd倍した結果のオブジェクトを返す
}
:
Monster slalin = new Monster();
slalin.hp = 10;
slalin.mp = 20;
slalin.hpx(5).mpx(2); //HPを5倍してからMPを2倍する
p.174 補足:thisの応用例② メソッドの引数とインスタンス変数を同じ名前にして識別する
・こうするとメソッドの引数にインスタンス変数と異なる名前を付ける必要がなくなる
・例:
class Monster {
public int hp, mp;
public setHP(int hp) { this.hp = hp; } //this.hpはインスタンス変数、hpは引数
public setMP(int mp) { this.mp = mp; } //this.hpはインスタンス変数、hpは引数
}
提出:アレンジ演習:p.173 destruct01.cs (どのバージョンでもOK)