從Groovy1.1beta-2開始,實現動態改變對象的能力變的十分簡單:
一開始,我們有這樣一個類:
class Person {
String name
}
該類的實例都是啞巴,不能說話,作為造物主的我們該完善它們,使它們能自我介紹(添加實例方法):class Person {
String name
}
// 添加自我介紹的行為
Person.metaClass.introduce << {println "I'm $name"}
現在讓我們看看,它們到底是否真的能夠開口自我介紹了呢:
class Person {
String name
}
// 添加自我介紹的行為
Person.metaClass.introduce << {println "I'm $name"}
def person = new Person(name:"山風小子")
person.introduce()
運行結果:
I'm 山風小子
嗯~人類改造成功~
但人應該有性別吧,嗯~對的,加個性別屬性sex(添加屬性):
class Person {
String name
}
// 添加自我介紹的行為
Person.metaClass.introduce << {println "I'm $name"}
// 添加性別屬性,默認為男(Male)
Person.metaClass.sex = "Male"
def person = new Person(name:"山風小子")
person.introduce()
println person.sex
運行結果:
I'm 山風小子
Male
但做男人累啊~為了買房,娶妻拼命賺錢,做女人算了,做變性手術:
class Person {
String name
}
// 添加自我介紹的行為
Person.metaClass.introduce << {println "I'm $name"}
// 添加性別屬性,默認為男(Male)
Person.metaClass.sex = "Male"
def person = new Person(name:"山風小子")
person.introduce()
println person.sex
// 做變性手術,變為女的(Female)
person.sex = "Female"
println person.sex
運行結果:
I'm 山風小子
Male
Female作為造物主的我們考慮到手術的風險性,為了讓其他人知道自己現在是個女的,在介紹中添加性別說明:
class Person {
String name
}
// 添加自我介紹的行為
Person.metaClass.introduce << {println "I'm $name"}
// 添加性別屬性,默認為男(Male)
Person.metaClass.sex = "Male"
// 修改之前自我介紹行為,添加性別說明
Person.metaClass.introduce << {println "I'm $name, $sex"}
def person = new Person(name:"山風小子")
person.introduce()
// 做變性手術,變為女的(Female)
person.sex = "Female"
person.introduce()
運行結果:
I'm 山風小子, Male
I'm 山風小子, Female
為了造人方便點,搞個工廠方法(添加類方法,即靜態方法):
class Person {
String name
}
// 添加自我介紹的行為
Person.metaClass.introduce << {println "I'm $name"}
// 添加性別屬性,默認為男(Male)
Person.metaClass.sex = "Male"
// 修改之前自我介紹行為,添加性別說明
Person.metaClass.introduce << {println "I'm $name, $sex"}
def person = new Person(name:"山風小子")
person.introduce()
// 做變性手術,變為女的(Female)
person.sex = "Female"
person.introduce()
// 工廠方法,造人方便點
Person.metaClass.'static'.createPerson = { name, sex ->
Person p = new Person()
p.name = name
p.sex = sex
return p
}
def bluesun = Person.createPerson("山風小子", "Male")
bluesun.introduce()
運行結果:
I'm 山風小子, Male
I'm 山風小子, Female
I'm 山風小子, Male
為了方便實例化Person,添加一個構造方法(添加構造方法):
class Person {
String name
}
// 添加自我介紹的行為
Person.metaClass.introduce << {println "I'm $name"}
// 添加性別屬性,默認為男(Male)
Person.metaClass.sex = "Male"
// 修改之前自我介紹行為,添加性別說明
Person.metaClass.introduce << {println "I'm $name, $sex"}
def person = new Person(name:"山風小子")
person.introduce()
// 做變性手術,變為女的(Female)
person.sex = "Female"
person.introduce()
// 工廠方法,造人方便點
Person.metaClass.'static'.createPerson = { name, sex ->
Person p = new Person()
p.name = name
p.sex = sex
return p
}
def bluesun = Person.createPerson("山風小子", "Male")
bluesun.introduce()
// 方便實例化Person,添加一個構造方法
Person.metaClass.constructor << { name, sex ->
new Person(name:name, sex:sex)
}
def daniel = new Person("Daniel", "Male")
daniel.introduce()
運行結果:
I'm 山風小子, Male
I'm 山風小子, Female
I'm 山風小子, Male
I'm Daniel, Male
最後,引用一個官方例子swapCase來展示一下Groovy是如何增強既有類的能力的(演示如何使用delegate,注意演示的是final類:String)
String.metaClass.swapCase = {->
def sb = new StringBuffer()
// delegate與this類似,引用當前正被‘改造’的對象
delegate.each {
sb << (Character.isUpperCase(it as char) ? Character.toLowerCase(it as char) :
Character.toUpperCase(it as char))
}
sb.toString()
}
String s = "Hello, world!"
println s.swapCase()
運行結果:
hELLO, WORLD!
<<用於添加方法(如果方法已經存在,會發生groovy.lang.GroovyRuntimeException異常),=用於添加方法或覆蓋既有方法
而從Groovy1.1beta-3開始,Groovy的動態性有了進一步的增強:
我們可以通過respondsTo和hasProperty方法來判斷是否存在某個方法和某個屬性:
class Person {
String name
public Person(name) {
this.name = name
}
def introduce() {
println "I'm $name"
}
def introduce(String name) {
println "She is $name"
}
}
def daniel = new Person('Daniel')
// 判斷實例daniel是否有方法introduce()
if (daniel.metaClass.respondsTo(daniel, 'introduce')) {
daniel.introduce()
}
// 判斷實例daniel是否有方法introduce(String)
if (daniel.metaClass.respondsTo(daniel, 'introduce', String)) {
daniel.introduce('Annie')
}
// 判斷實例daniel是否有屬性name
if (daniel.metaClass.hasProperty(daniel, 'name')) {
println daniel.name
}
運行結果:
I'm Daniel
She is Annie
Daniel
使用methodMissing方法來處理對那些不存在的方法的調用
class Person {
String name
public Person(name) {
this.name = name
}
def introduce() {
println "I'm $name"
}
def introduce(String name) {
println "She is $name"
}
}
Person.metaClass.methodMissing = { name, args ->
// 動態添加方法
Person.metaClass."$name" = { methodArgs ->
if ("hello".equals(name))
println "$methodArgs"
else {
def argList = Arrays.asList(methodArgs)
println "No method $name with ${argList*.class}"
}
}
delegate."$name"(args)
}
def daniel = new Person('Daniel')
daniel.hello("Leona")
daniel.hi("Annie", "Leona")
運行結果:
{"Leona"}
No method hi with [class java.lang.String, class java.lang.String]
類似地,使用propertyMissing方法來處理對那些不存在的屬性的引用
class Person {
String name
public Person(name) {
this.name = name
}
def introduce() {
println "I'm $name"
}
def introduce(String name) {
println "She is $name"
}
}
Person.metaClass.propertyMissing = { String name, value ->
// 動態添加屬性
Person.metaClass."$name" = value
}
def daniel = new Person('Daniel')
daniel.sex = 'Male'
println daniel.sex
運行結果:
Male