如前所述,MetaClass
在方法解析中起着核心作用。对于来自groovy代码的每个方法调用,groovy将找到给定对象的MetaClass
,并通过groovy.lang.MetaClass#invokeMethod(java.lang.Class,java.lang.Object,java.lang.String,java.lang.Object,boolean,boolean))将方法解析委托给MetaClass,groovy.lang.MetaClass#invokeMethod(java.lang.Class,java.lang.Object,java.lang.String,java.lang.Object,boolean,boolean))不应与groovy.lang.GroovyObject#invokeMethod(java.lang.String,java.lang.Object))混淆,groovy.lang.GroovyObject#invokeMethod(java.lang.String,java.lang.Object))恰好是元类最终可能调用的方法。
1.默认的metaclass的MetaClassImp
默认情况下,对象获取实现默认方法查找的MetaClassImpl
实例。这种方法查找包括在对象类(“常规”方法)中查找方法,但如果没有以这种方式找到方法,则会求助于调用methodMissing
,最终调用groovy.lang.GroovyObject#invokeMethod(java.lang.String,java.lang.Object))
class Foo {}
def f = new Foo()
assert f.metaClass =~ /MetaClassImpl/
2.自定义metaclasses
您可以更改任何对象或类的metaclass,并将其替换为 Metaclassgroovy.lang.MetaClass的自定义实现。通常,您需要扩展一个现有的metaclass,例如MetaClassImpl
、DelegatingMetaClass
、ExpandoMetaClass
或ProxyMetaClass
;否则,您将需要实现完整的方法查找逻辑。在使用新的metaclass实例之前,应该调用groovy.lang.MetaClass#initialize()),否则元类的行为可能会或可能不会像预期的那样。
2.1.委托metaclass
如果您只需要装饰现有的Metaclass,则可以DelegatingMetaClass
简化该用例。旧的元类实现仍然可以通过super
轻松地对输入应用预转换、路由到其他方法和后处理输出来访问。
class Foo { def bar() { "bar" } }
class MyFooMetaClass extends DelegatingMetaClass {
MyFooMetaClass(MetaClass metaClass) { super(metaClass) }
MyFooMetaClass(Class theClass) { super(theClass) }
Object invokeMethod(Object object, String methodName, Object[] args) {
def result = super.invokeMethod(object,methodName.toLowerCase(), args)
result.toUpperCase();
}
}
def mc = new MyFooMetaClass(Foo.metaClass)
mc.initialize()
Foo.metaClass = mc
def f = new Foo()
// 新的metaclass路由 BAR()和bar()的大写字母表示
assert f.BAR() == "BAR"
2.2.魔法包
可以在启动时更改元类,方法是为元类提供精心编制的(魔术)类名和包名。为了更改LLnteger的元类,在类路径中放置一个类mmletaclasetclass就足够了。例如,如果您想在框架执行代码之前更改元类,这在使用框架时非常有用。魔术包的一般形式是GGaclass。在下面的示例中,[包]是JJavalang,[类]是整数: