Java8:メソッド参照はオブジェクトを参照していない

2018年5月16日

良く考えれば理解できることなのだが、てきとーに考えていたので痛い目にあった。メモしておく。

メソッド参照は対象オブジェクトを参照していない。これは適切な言い方ではないかもしれないが、何と言えば良いのかわからない。

例えば、次のコードを実行してみる。

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と意味的には同じであることがわかる。深く考えずに弱参照で保持して痛い目に。。。