倭マン's BLOG

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

Groovy ノミックス (Class 編)

今回は Collection に突入しようかと思ってたんですが、前回メタクラスの流れにのって、GDK が Class クラスに追加しているメソッドを見ていきます。 今回見ていくメソッドは以下の通り:

boolean isCase(Object switchValue)

// インスタンス生成
Object newInstance()
Object newInstance(Object[] args)

// メタクラス
MetaClass getMetaClass()
void setMetaClass(MetaClass metaClass)
MetaClass metaClass(Closure closure)

// ミックイン
void mixin(Class categoryClass)
void mixin(List categoryClasses)
void mixin(Class[] categoryClass)
  • isCase() とメタクラス関連のメソッドは Object クラスのときに同じようなのが出てきました。 違いは後ほど。
  • newInstance() メソッドはインスタンスを生成するメソッドで、引数なしものは既に Class クラスに定義されています。 引数をとるものは java.lang.reflect.Constructor に似たものがありますね。
  • mixin は Object クラスでみた use() と同じく、カテゴリクラスの機能を混ぜ込むメソッドです。 Groovy ノミックスイン機能ですw

もう少し各メソッドを詳しく見てみると

メソッド 返り値 since 説明
isCase(Object) boolean 1.0 フィルタ
newInstance()
newInstance(Object[])
Object 1.0 インスタンス生成
getMetaClass()
setMetaClass(MetaClass)
metaClass(Closure)
MetaClass
void
MetaClass
1.5.0
1.6.0
1.6.0
メタクラスの取得・設定
mixin(Class)
mixin(List)
mixin(Class[])
void 1.6.0 カテゴリのミックスイン

それでは、各メソッドの使い方を簡単に見ていきましょう。 前回から引き続き、以下のような Person クラスを使います:

class Person{
    String name
    int age
}

あと、Groovy ではクラス・リテラルを参照する場合に「.class」をつける必要はありません。 「Person」とすると「Person.class」で返される Class オブジェクトが得られます。

isCase() メソッド

isCase() メソッドはフィルターとして使うメソッドで、Class クラスの場合、引数がこの Class クラスのインスタンスならば通すフィルターになります:

def waman = new Person(name:'倭マン', age:100)
assert Person.isCase(waman)
assert waman in Person

他にも switch-case 文で「case Person:」のように書くこともできます。 機能は同じで、switch 文に渡されたオブジェクトがこのクラスのインスタンスなら、その分岐を実行します。

newInstance() メソッド

newInstance() メソッドはそのクラスのインスタンスを生成するメソッドです。 引数なしのものはデフォルト・コンストラクタを、引数があるものはその引数にあったコンストラクタを呼び出してインスタンスを生成します:

def empty = Person.newInstance()
assert empty.name == null
assert empty.age == 0

def waman1 = Person.newInstance(name:'倭マン1', age:101)
assert waman1.name == '倭マン1'
assert waman1.age == 101

ドキュメントのいつのバージョンからか書いてませんが、Java 標準 API にも Class#newInstance() は定義されてますがね。

メタクラス関連のメソッド

メタクラス関連のメソッド

  • getMetaClass()
  • setMetaClass(MetaClass)
  • metaClass(Closure)

は前回に Object クラスで見たメソッドと同じです。 ただし、Class クラスに対してメタクラスの設定を行った場合、そのインスタンス全てに変更が施されます(ただし既にインスタンスが生成されている場合は影響を受けない)。 使い方は

Person.metaClass{
    introduce = { "My name is $delegate.name, $delegate.age years old." }
    greet = { Person someone -> "こんにちは、${someone.name}さん。" }
    greet = { String name, int age -> greeting(new Person(name:name, age:age)) }
}

def waman2 = new Person(name:'倭マン2', age:102)
assert waman2.introduce() == 'My name is 倭マン2, 102 years old.'

def waman3 = new Person(name:'倭マン3', age:103)
assert waman3.introduce() == 'My name is 倭マン3, 103 years old.'

使い方自体は Object クラスと同じです。

mixin

mixin (ミックスイン?ミクシン?)は、前回 use() メソッドの使い方で見たように、カテゴリクラスを用いて機能を追加するメソッドです。 前回の use() メソッドはクロージャーによってその機能追加のスコープを指定していましたが(w)、mixin はこれのグローバル・バージョン、すなわち全てのインスタンスに対してカテゴリクラスの機能を追加します。 こちらも mixin 前にインスタンス生成されている場合は機能が追加されません。 ではサンプル:

@Category(Person)
class PersonCategory{

    def greet(Person p){
        "こんにちは${p.name}さん。"
        // this でメソッドを呼び出されるオブジェクトを参照することも可
    }
}

Person.mixin PersonCategory    // mixin

def waman4 = new Person(name:'倭マン4', age:104)
def waman5 = new Person(name:'倭マン5', age:105)

assert waman4.greet(waman5) == 'こんにちは倭マン5さん。'

カテゴリクラスは前回の use() メソッドの箇所で説明したとおり @Category アノテーションを使用しなくても作成できますが、デフォルト・コンストラクタによってインスタンスが生成できないといけないようです。 つまり、前回見たように Files クラスのようなインスタンス生成を不可能にしてあるユーティリティ・クラスは使えません。

今回の Class クラスは前回の Object クラスのメタプログラミング用メソッドからの惰性でやってまいました。 次回こそは Collection を。

プログラミングGROOVY

プログラミングGROOVY