26 Nov 2014, 16:12

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

はじめに

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

コード

<div class="outline-text-3" id="text-unnumbered-2">
  <p>
    こんなコードを書いた. タイムアウトになったら, 自分自身を Set から削除する.
  </p>

  <p>
    [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221; ]<br /> import java.util.HashSet;<br /> import java.util.Set;<br /> import java.util.Collections;
  </p>

  <p>
    public class TimeoutObjectSample {<br /> public static void main (String[] args) {<br /> new B ();<br /> }<br /> }
  </p>

  <p>
    class B {<br /> Set<A> set;</p> 

    <p>
      public B () {<br /> set = Collections.synchronizedSet ( new HashSet<A>() );<br /> A a = new A (this);</p> 

      <p>
        set.add (a);<br /> System.out.println (&#8220;size is &#8221; + set.size ());<br /> a.start ();<br /> }
      </p>

      <p>
        public synchronized Set<A> getSet () {<br /> return set;<br /> }</p> 

        <p>
          }
        </p>

        <p>
          class A {<br /> B parent;
        </p>

        <p>
          public A (B parent) {<br /> this.parent = parent;<br /> }
        </p>

        <p>
          void start () {<br /> System.out.println (&#8220;start&#8221;);
        </p>

        <p>
          new Thread (new Runnable () {
        </p>

        <p>
          public void run () {<br /> try{<br /> Thread.sleep (1000);<br /> } catch (InterruptedException e){<br /> } finally {<br /> Set<A> set = parent.getSet ();<br /> System.out.println (&#8220;I will die&#8221;);<br /> set.remove (this);<br /> System.out.println (&#8220;size is &#8221; + set.size ());<br /> }<br /> }<br /> }).start ();<br /> }<br /> }<br /> [/sourcecode]</p> 

          <p>
            しかし, これがうまく動かない&#x2026; 期待値は最後に Set の要素数が 0 になること.
          </p>

          <p>
            [sourcecode language=&#8221;language&#8221; title=&#8221;&#8221; ]<br /> size is 1<br /> start<br /> I will die<br /> size is 1<br /> [/sourcecode]
          </p>

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

          <p>
            [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221; ]<br /> System.out.println (this);<br /> System.out.println (this.getClass ());<br /> [/sourcecode]
          </p>

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

          <p>
            [sourcecode language=&#8221;language&#8221; title=&#8221;&#8221; ]<br /> size is 1<br /> start<br /> A@5df86e79<br /> class A<br /> A$1@5f92b8f5<br /> class A$1<br /> I will die<br /> size is 1<br /> [/sourcecode]
          </p></div> </div> </div> 

          <div id="outline-container-unnumbered-3" class="outline-2">
            <h2 id="unnumbered-3">
              無名クラスに引数を渡す
            </h2>

            <div class="outline-text-2" id="text-unnumbered-3">
              <p>
                this でさす内容が違うならば, this をしなければよいのでは?? ということで, 無名クラスにパラメータを渡す方法をしらべる.
              </p>

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

              <ul class="org-ul">
                <li>
                  <a href="http://www58.atwiki.jp/chapati4it/pages/61.html">ちゃぱてぃ商店 IT 部 @ ウィキ &#8211; Java/ サンプル/ 無名クラスにパラメータを渡す</a>
                </li>
              </ul>

              <p>
                ということで以下を変更
              </p>

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

              <p>
                [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221; ]<br /> import java.util.HashSet;<br /> import java.util.Set;<br /> import java.util.Collections;
              </p>

              <p>
                public class TimeoutObjectSample {<br /> public static void main (String[] args) {<br /> new B ();<br /> }<br /> }
              </p>

              <p>
                class B {<br /> Set<A> set;</p> 

                <p>
                  public B () {<br /> set = Collections.synchronizedSet ( new HashSet<A>() );<br /> A a = new A (this);</p> 

                  <p>
                    set.add (a);<br /> System.out.println (&#8220;size is &#8221; + set.size ());<br /> a.start ();<br /> }
                  </p>

                  <p>
                    public synchronized Set<A> getSet () {<br /> return set;<br /> }</p> 

                    <p>
                      }
                    </p>

                    <p>
                      class A {<br /> B parent;
                    </p>

                    <p>
                      public A (B parent) {<br /> this.parent = parent;<br /> }
                    </p>

                    <p>
                      void start () {<br /> System.out.println (&#8220;start&#8221;);<br /> System.out.println (this);<br /> System.out.println (this.getClass ());
                    </p>

                    <p>
                      new Thread (new Runnable () {<br /> A a;<br /> int time;
                    </p>

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

                    <p>
                      public void run () {<br /> try{<br /> Thread.sleep (time);<br /> } catch (InterruptedException e){<br /> } finally {<br /> Set<A> set = parent.getSet ();<br /> System.out.println (&#8220;I will die&#8221;);<br /> set.remove (a);<br /> System.out.println (&#8220;size is &#8221; + set.size ());<br /> }<br /> }<br /> }.setParam (this, 1000)<br /> ).start ();<br /> }<br /> }<br /> [/sourcecode]</p> 

                      <p>
                        これでうまくいきました.
                      </p></div> </div>