理解 Groovy 元编程的 MetaClass

1,792 阅读2分钟

你应该已经知道,groovy是一种动态编程语言,使得我们可以在运行时期将任何方法添加到任何类。为了更好的理解 MetaClass。 从一个简单的元编程(MetaProgramming)示例开始,其中我们在Integer类中添加了一个方法(isEvent)。

// 一个无参方法.
Integer.metaClass.isEven = { -> 
delegate%2 == 0
}

可以思考一下,上面的 metaClass 是什么?deletegate 代理的是谁?元编程如何工作?怎样关闭元编程能力?inEven() 是静态方法还是实例方法?isEven() 是添加给特定对象吗?怎样给对象添加多个方法?如果知道或许你也不会打开这片文章😂😂,下面就来一一讲述:

什么是metaClass

在Groovy语言中,每个对象都有一个名称为metaClass的MetaClass类的对象。 此metaClass对象负责保存与该对象有关的所有信息。 每当您对该对象执行任何操作时,Groovy的调度机制都会通过该元类对象(metaClass)路由调用。 因此,如果要更改任何对象/类的行为,则必须更改附加到该类/对象的MetaClass对象,并且它将在运行时更改该类/对象的行为。

deletegate 代理的是谁

大白话来说,谁调用就代理谁(实例对象)。

元编程(MetaProgramming)如何工作

每个 Groovy 对象都有一个名为metaClass的MetaClass类的对象,所以当我们调用方法时,都会到 metaClass 保存的信息中查找。如果找到就会调用,比如上面的方法,可以这么用。

Integer.metaClass.isEven = { ->
delegate%2 == 0
}

int a = 10
int b = 11

println "a.isEven(): ${a.isEven()}"
println "b.isEven(): ${b.isEven()}"

输出结果如下:

a.isEven(): true
b.isEven(): false

这个也好理解嘛!对 2 求余数,偶数为0,奇数为1。

怎样关闭元编程能力

这个就相当简单了, 把 metaClass 置空就搞定了。

Integer.metaClass = null
// 这样就找不到方法定义了 No signature of method: java.lang.Integer.isEven() is applicable for argument types: () values: []
a.isEven() 

inEven() 是静态方法还是实例方法

inEven() 是实例方法,如果要定义静态方法,需要像下面这样:

Integer.metaClass.static.isEven = { number ->
    number%2 == 0
}
// 如果是静态方法,参数肯定就只能传进去了,而不能再通过实例调用啦!
Integer.isEven(1) // false
Integer.isEven(2) // true

isEven() 是添加给特定对象吗

isEven() 是添加到所有的 Interger 对象。如果只想给特定的对象添加,需要像下面这样:

Integer aNumber = 9
aNumber.metaClass.isEven = { ->
    delegate%2 == 0
}
println aNumber.isEven() // false
println 2.isEven() // will throw MissingMethodException.

怎样给对象添加多个方法

需要添加多个方法,可以像下面这样:

Integer.metaClass {
    isEven { -> delegate%2 == 0 }
    isOdd { -> delegate%2 != 0 }
    // other methods
}
 
println 6.isEven() // true
println 6.isOdd()  // false