Java の無名クラスにパラメータを渡す方法のメモ

    はじめに

    Java で, オブジェクト自体にタイムアウト機能を持たせることを考えた. (普通ならば, 外部のオブジェクトが監視するのかな??)

    コード

    こんなコードを書いた. タイムアウトになったら, 自分自身を Set から削除する.

    [sourcecode language=”java” title=”” ]
    import java.util.HashSet;
    import java.util.Set;
    import java.util.Collections;

    public class TimeoutObjectSample {
    public static void main (String[] args) {
    new B ();
    }
    }

    class B {
    Set set;

    public B () {
    set = Collections.synchronizedSet ( new HashSet
    () );
    A a = new A (this);

    set.add (a);
    System.out.println (“size is ” + set.size ());
    a.start ();
    }

    public synchronized Set getSet () {
    return set;
    }

    }

    class A {
    B parent;

    public A (B parent) {
    this.parent = parent;
    }

    void start () {
    System.out.println (“start”);

    new Thread (new Runnable () {

    public void run () {
    try{
    Thread.sleep (1000);
    } catch (InterruptedException e){
    } finally {
    Set
    set = parent.getSet ();
    System.out.println (“I will die”);
    set.remove (this);
    System.out.println (“size is ” + set.size ());
    }
    }
    }).start ();
    }
    }
    [/sourcecode]

    しかし, これがうまく動かない… 期待値は最後に Set の要素数が 0 になること.

    [sourcecode language=”language” title=”” ]
    size is 1
    start
    I will die
    size is 1
    [/sourcecode]

    もう少し調べてみる. 以下を Thread の内部と外に仕込んだ.

    [sourcecode language=”java” title=”” ]
    System.out.println (this);
    System.out.println (this.getClass ());
    [/sourcecode]

    どうも Runnable () クラスの内部と外部では, this を呼んでも別のクラスをさしているようだ.

    [sourcecode language=”language” title=”” ]
    size is 1
    start
    A@5df86e79
    class A
    A$1@5f92b8f5
    class A$1
    I will die
    size is 1
    [/sourcecode]

    無名クラスに引数を渡す

    this でさす内容が違うならば, this をしなければよいのでは?? ということで, 無名クラスにパラメータを渡す方法をしらべる.

    どうやら, 無名クラスのなかに, メソッドを定義すればよいようだ.

    ということで以下を変更

    • 無名クラスのなかに, パラメータをうけとる属性を作成
    • 無名クラスのメソッドでパラメータをセットする setter を作成. このメソッドは自分自身 (Runnnable) を返す.
    • スレッドを起動する前に, パラメータをセットする.

    [sourcecode language=”java” title=”” ]
    import java.util.HashSet;
    import java.util.Set;
    import java.util.Collections;

    public class TimeoutObjectSample {
    public static void main (String[] args) {
    new B ();
    }
    }

    class B {
    Set set;

    public B () {
    set = Collections.synchronizedSet ( new HashSet
    () );
    A a = new A (this);

    set.add (a);
    System.out.println (“size is ” + set.size ());
    a.start ();
    }

    public synchronized Set getSet () {
    return set;
    }

    }

    class A {
    B parent;

    public A (B parent) {
    this.parent = parent;
    }

    void start () {
    System.out.println (“start”);
    System.out.println (this);
    System.out.println (this.getClass ());

    new Thread (new Runnable () {
    A a;
    int time;

    public Runnable setParam (A a, int time) {
    this.a = a;
    this.time = time;
    // 自分自身を返す.
    return this;
    }

    public void run () {
    try{
    Thread.sleep (time);
    } catch (InterruptedException e){
    } finally {
    Set
    set = parent.getSet ();
    System.out.println (“I will die”);
    set.remove (a);
    System.out.println (“size is ” + set.size ());
    }
    }
    }.setParam (this, 1000)
    ).start ();
    }
    }
    [/sourcecode]

    これでうまくいきました.