finalize()
これは期待どおりに機能し、このメソッドが Java の他のメソッドと異なって扱われるとは思いません。少し異なると考えられるのは、 JavaDocfinalize()
で概説されているように、メソッドは通常、JVM ガベージ コレクター自体によってのみ呼び出されることです。
オブジェクトへの参照がなくなったとガベージ コレクションが判断したときに、オブジェクトのガベージ コレクタによって呼び出されます。
Josh Bloch が、 Effective Javaでのファイナライザーの使用に対して強く警告していることにも注意してください。
ファイナライザは予測不可能で、危険であることが多く、一般的に不要です。それらを使用すると、動作が不安定になり、パフォーマンスが低下し、移植性の問題が発生する可能性があります。ファイナライザーには有効な用途がいくつかありますが、経験則として、ファイナライザーは避けるべきです。
あなたの例に似た次の例を考えてみましょう。
オーバーライドされたfinalize()
メソッドを持つ基本クラス。
public abstract class BaseClass {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("BaseClass finalisation occured");
}
}
finalize をオーバーライドしないサブクラス:
public class SubClass extends BaseClass {
public void foo() {
System.out.println("SubClass Foo'd");
}
}
そして、すべてを実行するための基本的な main メソッドを持つドライバー クラス:
public class Driver {
public static void main(String[] args) {
SubClass sc = new SubClass();
sc.foo();
sc = null;
System.gc();
}
}
得られる出力は次のとおりです。
SubClass Foo'd
BaseClass finalisation occured
Java メソッド ルックアップで (非常に簡単に言えば) 何が起こるかというと、現在のクラスで任意のメソッドが検索され、そうでない場合は、必要なメソッドが見つかるまでクラス階層を上っていくということです。上記の例では、メソッドがオブジェクトでfoo()
呼び出されると、実装が使用されるようにクラスにメソッド定義が含まれており、クラス階層がそれ以上上がらないようになっています。メソッドが呼び出されると ( a が要求されたため) 、メソッドは最初にクラスで検索されますが、そのメソッドにはその親の実装が含まれていないため( ) が検索されます。do には使用される soの実装が含まれており、1 行が stdout に出力されます。SubClass
SubClass
finalize()
System.gc()
SubClass
finalize()
BaseClass
BaseClass
finalize()
ここで、再度オーバーライドするサブサブクラスを考えてみましょうfinalize()
:
public class OverridenSubClass extends SubClass {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("Overriden finalize called, which calls super's finalize first");
}
}
そして、わずかに変更されたDriver
クラス:
public class Driver {
public static void main(String[] args) {
OverridenSubClass sc = new OverridenSubClass();
sc.foo();
System.out.println(sc.toString());
sc = null;
System.gc();
System.exit(0);
}
}
次の出力が生成されます。
SubClass Foo'd
finalize.OverridenSubClass@7150bd4d
BaseClass finalisation occured
Overriden finalize called, which calls initial finalize first
うまくいけば、これは期待どおりです。ここで注目すべき唯一の興味深い点は次のとおりです。
toString()
どのクラスでもオーバーライドしないため、Object.toString()
実装が使用されます。
- 変数の型は、使用されるメソッドの実装を決定するものではありません。それは、によって参照される
sc
実際のオブジェクトの型です。sc