Java8:メソッド参照はオブジェクトを参照していない
良く考えれば理解できることなのだが、てきとーに考えていたので痛い目にあった。メモしておく。
メソッド参照は対象オブジェクトを参照していない。これは適切な言い方ではないかもしれないが、何と言えば良いのかわからない。
例えば、次のコードを実行してみる。
package samples;
import java.lang.ref.*;
public class Dissapear {
public static void main(String[]args) throws Exception {
// ここで強い参照
Foo foo = new Foo();
// 弱い参照いろいろ
WeakReference<Foo>w1 = new WeakReference<>(foo);
WeakReference<Runnable>w2 = new WeakReference<>(foo::bar);
WeakReference<Runnable>w3 = new WeakReference<>(()->foo.bar());
WeakReference<Runnable>w4 = new WeakReference<>(new Runnable() {
public void run() {
foo.bar();
}
});
while (true) {
System.out.println("w1:" + w1.get());
System.out.println("w2:" + w2.get());
System.out.println("w3:" + w3.get());
System.out.println("w4:" + w3.get());
Thread.sleep(1000);
System.gc();
}
}
public static class Foo {
public void bar() {}
}
}
実行結果は以下になる。
w1:samples.Dissapear$Foo@87aac27
w2:samples.Dissapear$$Lambda$1/1418481495@3e3abc88
w3:samples.Dissapear$$Lambda$2/135721597@6ce253f1
w4:samples.Dissapear$$Lambda$2/135721597@6ce253f1
w1:samples.Dissapear$Foo@87aac27
w2:null
w3:null
w4:null
w1:samples.Dissapear$Foo@87aac27
w2:null
w3:null
w4:null
...
fooは最初に強い参照があるので、w1はいつまでも保持されているのだが、他は全滅である。
w4は、その字面からも全く別のオブジェクトを弱参照しているので、回収されてしまうのはわかるのだが、しかし、w2は保持されているだろうと良くかんがえもせずに思い込んでいた。
いかにもfooに対して参照しているかのような見かけになっているからだ。
しかし、良く考えればw3、w4と意味的には同じであることがわかる。深く考えずに弱参照で保持して痛い目に。。。