倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

@Delegate アノテーションの異常な使い方

@Delegate アノテーションをチョット使ってみて思ったことをメモ。 第2弾。

正常な使い方


まずは @Delegate の正常な使い方。

interface Animal{
    def bark()
}

class Dog implements Animal{
    def bark(){
        println 'ワンワン!'
    }
}

class AnimalMobileSuit{
    @Delegate Animal delegate = new Dog()
}

def dog = new AnimalMobileSuit()
dog.bark()    // 「ワンワン!」と表示される
println dog instanceof Animal    // true と表示される
  • AnimalBobileSuit クラスに bark() メソッドを定義する必要がないよwwwってのが @Delegate の便利さ。
  • @Delegate アノテーションを使うと、自動的に(勝手に) AnimalMobileSuit クラスが Animal 型を実装していることになる*1
  • これが嫌な場合は @Delegate(interfaces = false) としよう。

異常な使い方


さて、以降で見ていくのはどういう場合かというと、委譲するクラスが Animal インターフェースを implements している場合です。 委譲するクラスは「正常な使い方」の例では AnimalMobileSuit クラスです(以下の例では AnimalAndroid クラス)。

@Delegate を使用した結果 Animal 型を実装するんだから、特に問題なさそうな気がするんですが、普通にやるとコンパイルエラーが出てしまいます。 まぁ、サンプルコードと一緒に見ていった方がいいかな。

その1

単純に「implements Animal」を付けてみる:

class AnimalAndroid implements Animal{    // コンパイルエラー
    @Delegate Animal delegate = new Dog()
}

def android = new AnimalAndroid()
android.bark()

すると、「AnimalAndroid クラスが bark() メソッドを実装していない」旨のコンパイルエラー・メッセージが出ます。 実行もできません。 将来、コンパイラが @Delegate を感知して適切な処理をしてくれるようになりそうな気もするんだけど、何かまずいのかな? とりあえず、現在はコンパイルエラー

その2

bark() メソッドを実装してみる:

class AnimalAndroid implements Animal{
    @Delegate Animal delegate = new Dog()

    def bark(){
        delegate.bark()
    }
}

def android = new AnimalAndroid()
android.bark()   // 「ワンワン!」と表示される

よし、これでぱっちり。 @Delegate の意味が無い以外は。

その3

「その1」でコンパイルエラー・メッセージが「abstract でないのに bark() メソッドがない」というメッセージだったので、AnimalAndroid を abstract にしてみる:

abstract class AnimalAndroid implements Animal{    // 抽象クラスにする
    @Delegate Animal delegate = new Dog()
}

def android = new AnimalAndroid()    // コンパイルエラー
android.bark()

AnimalAndroid クラス自体はコンパイルエラーがなくなったけど、今度はそのインスタンスを作成する際にコンパイルエラーが。 まぁ、抽象クラスのインスタンス化ってできないからねぇ。

その4

さて、以上の話を踏まえて、解決策(になってるかな?)。 k2juniorの日記「Javaマニア度 判定問題」を参考にして、抽象クラスである AnimalAndoriod を使って無名クラスを作成します:

abstract class AnimalAndroid implements Animal{    // 抽象クラスにする
    @Delegate Animal delegate = new Dog()
}

def android = new AnimalAndroid(){}    // AnimalAndroid を使って無名クラスを作成する
android.bark()  // 「ワンワン!」と表示される

これでコンパイルエラーがなくなり、実行も可能になってめでたしめでたし! ただ、InteliJ IDEA Community Ed. では、無名クラスの作成部分でコンパイルエラーが表示されるのが難点(実行はできるんだけど)。 警告じゃないので抑制もできなさそう・・・

Groovyイン・アクション

Groovyイン・アクション


Grails徹底入門

Grails徹底入門

  • 作者: 山田正樹,山本剛,上原潤二,永井昌子,杉山清美,杉浦孝博,笠原史郎,香月孝太,福岡竜一,伊堂寺北斗
  • 出版社/メーカー: 翔泳社
  • 発売日: 2008/08/26
  • メディア: 大型本
  • 購入: 3人 クリック: 42回
  • この商品を含むブログ (28件) を見る

*1:バイトコードレベルでは実際に実装している