デストラクタの特徴とは?C#・Javaでの使い方も解説!

- プログラマー
- コンストラクタなら聞いたことがありますが、デストラクタとは何でしょうか……?
- プロジェクト
マネージャー - デストラクタはC#でメモリの管理を行う際に使うメソッドですね。注意点もあるので、ここで使い方を覚えておきましょう!
C#のデストラクタとは
はじめに、デストラクタについて知識を入れておきましょう。デストラクタ(ファイナライザ)とは、ガベージコレクターによってインスタンスが破棄されるときに呼び出されるメソッドです。
【知識】
ガベージコレクター…プログラムが動的に確保したメモリ領域を解放する機能「ガベージコレクション」を行うもの。
デストラクタとコンストラクタとの違い
デストラクタと同様にインスタンスのリソース管理にかかわる機能として、コンストラクタというものがあります。このコンストラクタは、デストラクタとは違い、インスタンスが生成されるときに呼ばれるメソッドです。基本的にはクラス内パラメータの既定値設定等で使われますが、2回以上インスタンスを生成できないクラス(シングルトンクラス)の実現等にも利用されます。
デストラクタの特徴7つ
ここまでデストラクタの役割について紹介してきましたが、実際に使用する際は通常のメソッドとは異なる性質を持つため注意が必要です。ここでは、デストラクタの特徴を7つ紹介します。
1:実行の指定はできない
デストラクタの呼び出しタイミングをプログラマが制御することはできません。デストラクタがいつ呼ばれるかは、ガベージコレクター次第になります。ただし、少なくとも該当インスタンスがアプリケーション内で使用される可能性がある(参照元が存在する)間は実行されません。つまり、デストラクタの実行タイミングは、ガベージコレクターが該当インスタンスを終了処理が可能なオブジェクトであると判断したときとなります。
2:1つのデストラクタにつき1つのクラスで使う
デストラクタは1つのクラスで1つのみ使用できます。1つのクラスにデストラクタを多重定義することはできません。
なお、コンストラクタは1つのクラスに対して多重定義ができます。
3:使用できるのはクラスのみ
デストラクタはクラスでのみ使用ができます。構造体では定義することも使用することもできません。
なお、コンストラクタは構造体でも定義および使用ができます。
4:Java ではファイナライザと呼ばれる
Javaでは全クラスの継承元(基底クラス)であるObjectクラスのfinalizeメソッドがデストラクタの役割を担い、ファイナライザと呼ばれます。C#のデストラクタ同様にガベージコレクターにより使用されないと判断されたときに実行されます。
5:引数や戻り値を持たない
前述の通り、デストラクタはアプリケーションが呼び出すものではなくシステム側のガベージコレクターが呼び出すものですので、引数と戻り値を持たせることはできません。また、修飾子も持ちません。
なお、コンストラクタは引数を持つものを定義できます。戻り値は持ちません。
6:頭にチルダを付ける決まりがある
デストラクタの名前はクラス名の頭にチルダを付与したものになります。例えば、「Test」というクラスでデストラクタを定義する場合は「~Test()」とすることになります。
なお、コンストラクタはクラス名と同名になります。
7:自分で定義しない場合は自動で生成される
デストラクタは必ず明示的な定義が必要なものではありません。特に処理が必要なければ宣言は不要です。定義しない場合でデストラクタが呼ばれた場合は、暗黙的に継承チェーンの全インスタンスにあるデストラクタを呼び出すものとして解釈されます。
以上、デストラクタの特徴を7つ紹介しました。とはいえ、あまりピンと来ないと思いますので、さっそく次項でサンプルプログラムを紹介します。
C#のデストラクタの使用例
ここでは、実際にデストラクタを使用し、その役割について解説していきたいと思います。デストラクタは以下のように、クラス名の前に「~」を付けて定義します。
1 2 3 4 5 6 7 8 |
class SampleClass { ~SampleClass() // デストラクタ { // 処理 } } |
では、デストラクタを呼んでみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
using System; namespace FinalizeSample { class Finalizer { static void Main() { Console.WriteLine("1"); // コンストラクタの呼び出し Program program = new Program(); Console.WriteLine("2"); // programインスタンスは利用されなくなる program = null; Console.WriteLine("3"); Console.WriteLine("4"); Console.WriteLine("5"); Console.ReadLine(); } } class Program { // コンストラクタの定義 public Program() { Console.WriteLine("コンストラクタが呼ばれたよ"); } ~Program() { Console.WriteLine("デストラクタが呼ばれたよ"); } } } |
そして、こちらが実行結果です。
上画像の通り、この場合ではデストラクタは呼び出されないことが分かります。これは前述のデストラクタは「いつ呼び出されるか分からない」という特徴によるものです。そのため、アンマネージリソースで使用するのは控えるようにしましょう。
Javaでのデストラクタの使い方
Javaでデストラクタ(ファイナライザ)を使用する場合は以下のようにfinalizeメソッドを実装します。
1 2 3 4 5 6 7 |
public class SampleClass { public void finalize() { // 処理 } } |
デストラクタを呼び出す
では、デストラクタを呼んでみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package finalizeSample; public class Finalizer { public static void main(String[] args) { System.out.println("1"); // コンストラクタの呼び出し Program program = new Program(); System.out.println("2"); // programインスタンスは利用されなくなる program = null; System.out.println("3"); System.out.println("4"); System.out.println("5"); System.gc(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package finalizeSample; public class Program { // コンストラクタの定義 public Program() { System.out.println("コンストラクタが呼ばれたよ"); } public void finalize() { System.out.println("ファイナライザが呼ばれたよ"); } } |
ただし、このプログラムの実行結果もC#のときと全く同じとなります。これはJavaでもC#と同じく、デストラクタは「いつ呼び出されるか分からない」ためになります。
try-with-resources文を利用したリソース管理
一般的にプログラミングでは確保したリソースはfreeやdeleteといった関数・演算子を使って解放します。しかし、この方法は解放処理が意図せず複数回呼ばれ、メモリ領域が壊れてしまう(二重解放となる)危険性があります。
そこでJavaでは、特定のリソースをスコープ内でしか使用しないことを明示的に示す書き方として、try-with-resources文があります。これを利用することで、リソースを確実に閉じつつも複数回解放してしまう危険性を防げます。では、実際に例を見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package finalizeSample; import java.io.IOException; public class Finalizer2 { public static void main(String[] args) { System.out.println("1"); // コンストラクタの呼び出し try (Program2 program = new Program2()) { System.out.println("2"); } catch (IOException e) { // エラー・例外処理 } // programインスタンスは利用されなくなる System.out.println("3"); System.out.println("4"); System.out.println("5"); System.gc(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
package finalizeSample; import java.io.Closeable; import java.io.IOException; public class Program2 implements Closeable { // コンストラクタの定義 public Program2() { System.out.println("コンストラクタが呼ばれたよ"); } public void finalize() { System.out.println("ファイナライザが呼ばれたよ"); } @Override public void close() throws IOException { System.out.println("クローズ処理が呼ばれたよ"); } } |
そして、実行結果は以下のようになります。
1 2 3 4 5 6 7 8 |
1 コンストラクタが呼ばれたよ 2 クローズ処理が呼ばれたよ 3 4 5 ファイナライザが呼ばれたよ |
スコープを抜けた段階でクローズ処理が呼ばれていることが分かります。ただし、この時点でデストラクタは呼ばれないことに注意が必要です。デストラクタが呼ばれるタイミングはあくまでシステムのガベージコレクターに依存します。(例ではSystem.gcメソッドを利用して、アプリケーション側からガベージコレクターを実行させています)
デストラクタを使用するときの注意点
アプリケーションが外部リソースを使用する場合、デストラクタを明示的に定義し、そこでリソースの開放処理を記述する必要があります。その記述がない場合、インスタンスの生成と破棄を繰り返すうちに外部リソースを使用し続けてメモリ解放が起きない、いわゆるメモリリーク等のリソース問題の原因となる可能性があります。
- プログラマー
- あれ、デストラクタが呼ばれていませんね……。
- プロジェクト
マネージャー - 先ほど説明したとおり、デストラクタは「いつ呼び出されるか分からない」という特徴があります。アンマネージリソースで使用するのは控えるようにしましょう。
デストラクタは確実にインスタンスを破棄してくれるメソッド
今回はデストラクタの概要から使い方までを解説していきました。デストラクタは確実にインスタンスを破棄してくれるメソッドです。しかし、「いつ実行されるか分からない」というデメリットもあるため、Disposeメソッドを呼び出すusingと一緒に使用するようにしてください。
FEnet.NETナビ・.NETコラムは株式会社オープンアップシステムが運営しています。
株式会社オープンアップシステムはこんな会社です
秋葉原オフィスには株式会社オープンアップシステムをはじめグループのIT企業が集結!
数多くのエンジニアが集まります。

-
スマホアプリから業務系システムまで
スマホアプリから業務系システムまで開発案件多数。システムエンジニア・プログラマーとしての多彩なキャリアパスがあります。
-
充実した研修制度
毎年、IT技術のトレンドや社員の要望に合わせて、カリキュラムを刷新し展開しています。社内講師の丁寧なサポートを受けながら、自分のペースで学ぶことができます。
-
資格取得を応援
スキルアップしたい社員を応援するために資格取得一時金制度を設けています。受験料(実費)と合わせて資格レベルに合わせた最大10万円の一時金も支給しています。
-
東証プライム上場企業グループ
オープンアップシステムは東証プライム上場「株式会社オープンアップグループ」のグループ企業です。
安定した経営基盤とグループ間のスムーズな連携でコロナ禍でも安定した雇用を実現させています。
株式会社オープンアップシステムに興味を持った方へ
株式会社オープンアップシステムでは、開発系エンジニア・プログラマを募集しています。
年収をアップしたい!スキルアップしたい!大手の上流案件にチャレンジしたい!
まずは話だけでも聞いてみたい場合もOK。お気軽にご登録ください。


C#新着案件New Job
システム開発/東京都新宿区/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円東京都新宿区(新宿駅)システム開発/東京都新宿区/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円東京都新宿区(新宿駅)デバック、テスト項目の作成/神奈川県横浜市/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円神奈川県横浜市(桜木町駅)デバック、テスト項目の作成/神奈川県横浜市/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円神奈川県横浜市(桜木町駅)基幹システム開発導入/東京都新宿区/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円東京都新宿区(西新宿駅)基幹システム開発導入/東京都新宿区/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円東京都新宿区(西新宿駅)