読者です 読者をやめる 読者になる 読者になる

yashigani?.days

週刊少年ジャンプについてだらだら書きます

Javaの匿名クラスめっちゃ便利やしめっちゃ使う!

Java には匿名クラスってその場でサブクラスを作ってめっちゃ便利な機能があった
前に Android やったときにサンプルソースとかでイベントリスナをつけるのにコンストラクタの引数にクラスみたいなんが書いてあって,「なんじゃこりゃ!」と思ってたけど匿名クラスだった
JFrame を初期化して,それにマウスリスナをセットするというコードがこういう風に書ける

import javax.swing.*;
import java.awt.event.*;

class MyFrame {
  public static void main(String args[]) {
    JFrame frame = new JFrame("my frame") { 
      { 
        setBounds(100, 100, 200, 100); 
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        setVisible(true); 
      } 
    };
    frame.addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent e) { System.out.println("mouse clicked!"); }
    } );
  }
}


JFrame のコンストラクタにくっついてるのはインスタンス初期化ブロックってのを使っていい感じに初期化できてカッコいい
addMouseListener のとこはもうちょっと込み入ったことしてて,MouseAdapter のサブクラスを作って mouseClicked メソッドをオーバーライドしてる
普通は MouseAdapter を extends したクラスを作ってそのオブジェクトを突っ込むけど,ちょっとなんかしたいだけならいちいちクラスを作るのもあれだし,いい感じ
簡単な TimerTask なんか相性良さそう


どうなってんのか調べてみると,コンストラクタが呼び出される前に呼び出される...らしい
匿名クラスはそのサブクラスになるってことは

class SubFrame extends JFrame {
  public SubFrame(String title) {
    setBounds(100, 100, 200, 100);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setVisible(true);

    super(title);
  }
}

こういうことかと思って試してみたけど,super()は最初だろ馬鹿って怒られた
じゃあ,super() がコンストラクタの先頭にくるだけ?
よくわかんないからあとで調べる


インスタンス初期化ブロックには

ArrayList<String> array = new ArrayList<String>() { { add("text1"); add("text2"); ... } };

みたいな使い方もあるけど,普通は変数を add したくなると思う
そういうときは

class MyClass {
  void method() {
    final String text1 = "text1";
    String text2 = "text2";

    ArrayList<String> array = ArrayList<String>() {
      { add(text1); add(MyClass.this.text2); }
    };
  }
}

みたくする
text2 の記述の仕方がポイント
詳しくはインナークラスとかでググるとわかる


初期化のためにメソッドコールを連発することはよくあるし,その分変数名をタイプしなくて済んで精神汚染から開放される
ただ,}); みたいになったりで気持ち悪い記述になるのが玉に瑕
そのせいかわからんけど,あちこちで可読性が落ちるって意見があった
こう書いたほうが気持ち悪いけど意図は汲み取りやすいと思うしどんどん使ったほうがいいと思う