系列文章往这看
简介
Groovy的元编程是指groovy运行时,可以理解成编写代码所执行的时期,也就是Runtime。在比如有解释执行的Js,编译执行的java,还有运行时期执行的代码java反射。
Groovy运行时的处理逻辑如下图:
元编程
按照上图所示,我们可以自己写一个Demo,示例代码如下:
class Study {
public static void main(String[] args) {
def person = new Personal(name: "Silence", age: 26)
println(person.printName())
println(person.printAge())
println(person.sex)
}
}
class Personal {
public String name
public int age
public String printName() {
return "My name is $name"
}
public String printAge() {
return "My ag is $age"
}
}
输出结果如下:
My name is Silence
My ag is 26
Exception in thread "main" groovy.lang.MissingPropertyException: No such property: sex for class: Personal
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:65)
at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:87)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:329)
at Study.main(Study.groovy:9)
可以看到前两个日志是正常输出的,第三个控制台则提示MissingPropertyException。也就是上图中,所以逻辑都没进去导致异常输出。
我们在看看如果我们复写invokeMethod方法时的输出效果,代码修改如下:
class Personal {
public String name
public int age
public String printName() {
return "My name is $name"
}
public String printAge() {
return "My ag is $age"
}
@Override
Object invokeMethod(String name, Object args) {
return "this invoke method is $name,this params is $args"
}
}
控制台输出如下:
My name is Silence
My ag is 26
this invoke method is sex,this params is []
然后我们看看重写methodMissing方法后:
class Personal {
public String name
public int age
public String printName() {
return "My name is $name"
}
public String printAge() {
return "My ag is $age"
}
@Override
Object invokeMethod(String name, Object args) {
return "this invoke method is $name,this params is $args"
}
Object methodMissing(String name, Object args) {
return "this Missing method is $name,this params is $args"
}
}
输出结果如下:
My name is Silence
My ag is 26
this Missing method is sex,this params is []
可以看出,两个方法都重写时,优先调用methodMissing。如果找不到才会调用invokeMethod。
MetaClass
Metaclasses在方法解析中起到核心作用,对于来自groovy代码的每个方法调用,Groovy将找到给定对象的MetaClass,并通过MetaClass#invokeMethod将方法解析委托给Metaclasses,不应该与GroovyObject#invokeMethod混淆,后者恰好是Metaclasses最终可能调用的方法。
注入新字段
现在我们通过metaClass给Personal注入一个新属性看看:
Personal.metaClass.sex = "男"
def person = new Personal(name: "Silence", age: 26)
println(person.printName())
println(person.printAge())
println(person.sex)
可以看出我们注入了一个sex的字段,输入结果如下:
My name is Silence
My age is 26
男
当然了,注入静态变量也是类似,加上static即可。
注入新方法
看到我们输入性别的时候,发现好像和上面对比,不工整,那就自己整一个工整的,修改代码:
Personal.metaClass.sex = "男"
Personal.metaClass.printSex = { ->
"My sex is $sex"
}
def person = new Personal(name: "Silence", age: 26)
println(person.printName())
println(person.printAge())
println(person.printSex())
输出结果可想而之:
My name is Silence
My age is 26
My sex is 男
这下工整了~。当然了,注入静态方法也是类似,加上static即可。
总结
可以看出,我们可以通过metaClass给类新增变量,新增方法。那么这个和直接在类这种提供有什么区别呢?
举个例子:引入第三方库,其中的某个类有我们想用的方法,但是这个方法又不够全,想给里面添加点自己的方法。通常是extends它进而扩展,但是如果是final 类,任何类不能继承它,只能用它已有的方法。这个时候groovy的动态添加就有了大展身手的地方。不修改、不继承,通过metaclass变相的对原有的类进行了扩展。
参考
本文首发于我的个人博客:Gradle入门之Groovy元编程
更多文章请关注我的公众号:码农职场