Groovy 动态面向对象复盘总结

本文介绍了Groovy中使用import与as关键字进行类型别名的特性,以及如何解决类名冲突问题。此外,还探讨了Groovy的多态、复合方法、GroovyBean的使用、元类MetaClass和元程序编程,展示了其灵活的动态行为和方法调用的拦截与中转机制。
摘要由CSDN通过智能技术生成

import groovy.util.*

import java.math.BigInteger

import java.math.BigDecimal

在 Groovy 中的 import 语句有另外一个强大的作用,它可以与 as 关键字一起使用,这可以用来作为类型的别名,而一般的 import 语句运行使用类的名称来应用来,通过类型别名你可以使用任何你喜欢的名称来引用一个类,这个特性解决了类名称冲突的问题并且支持本地修改一个第三方类库的特性。

//------------ 支持本地修改一个第三方类库的特性案例 ------------

package thirdparty

class MathLib {

Integer twice(Integer value) {

return value * 3 // intentionally wrong!

}

Integer half(Integer value) {

return value / 2

}

}

assert 10 == new MathLib().twice(5) //false

assert 2 == new MathLib().half(4) //true

//我们可以使用类型别名来重命名原始的类,然后使用继承来修复它,不用修改原来已经使用的代码。

import thirdparty.MathLib as OriginalMathLib

class MathLib extends OriginalMathLib {

Integer twice(Integer value) {

return value * 2 // fix third bug

}

}

assert 10 == new MathLib().twice(5) //true

assert 2 == new MathLib().half(4) //true

//----------------- 类名称冲突的问题案例 ------------------

//假设我们需要使用下面的额外的数学库

package thirdparty2

class MathLib {

Integer increment(Integer value) {

return value + 1

}

}

//上面的类虽然它在不同的包中,但是有一个与前面的类型相同的名称,

//如果不使用别名,那么我们在代码中必须有一个类使用全限定名称或者两个都使用全限定名称,

//通过别名,我们可以通过一种优雅的方式来避免这种情况。

import thirdparty.MathLib as T1MathLib

import thirdparty2.MathLib as T2MathLib

assert 3 == new T1MathLib().half(new T2MathLib().increment(5)) //true

高级 OO 特性


Groovy 除过具备 Java OO 的特性外,自己还有一些额外的特性。

Multimethods

Groovy 的方法查找是方法参数的动态类型化,而 java 是静态类型的,这个 groovy 的特性叫做复合方法 Multimethods。

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

def func(Object obj) {

return ‘object’

}

def func(String str) {

return ‘string’

}

Object x = 1

Object y = ‘foo’

assert ‘object’ == func(x)

assert ‘string’ == func(y) // groovy 中 true,java 中 func(y) 返回 object

参数 x 是 Object 静态类型和 Integer 动态类型,参数 y 是 Object 静态类型和 String 动态类型。两个参数有相同的静态类型,两次都采用与 java 等价的方式传递给 func(Object),由于 groovy 通过动态类型进行方法分派,所以 func(String) 的专门实现被用在第二中情况。

可以看到,调用 func 方法的地方可能完全不知道其差异,从一个调用者的角度看,它就像 func(String) 覆盖了 func(Object),这在 java 中是办不到的。所以在 groovy 中通过这种能力,能使我们通过适当的覆盖行为更好的避免重复的代码。

GroovyBean 特性

Groovy 通过特定的语言支持使得 JavaBean 的使用更加简单,这种使用包含了三个方面:

  • 创建 JavaBean 类特殊的 Groovy 语法;

  • 不管 JavaBean 是在 groovy 中还是在 java 中声明的,groovy 提供了容易访问 Bean 的机制;

  • 对 JavaBean 的事件处理提供支持;

一般我们都是通过.进行属性访问,但是也有一些特例,我们还可以通过.@进行属性访问,譬如:

class Bean {

public value

void setValue(value) {

this.value = value

}

void getValue() {

value * 2

}

}

def bean = new Bean(value: 100)

assert 200 == bean.value

assert 100 == bean.@value

上面例子其实就是 Groovy 的一个特例规则,**在类内部,引用fieldName或者this.fieldName将被解释为直接属性访问,而不是 bean 风格的属性访问(通过访问方法进行);在类的外部,可以使用reference.@fieldName语法直接访问类属性,而不是 bean 风格的属性访问(通过访问方法进行)。

Groovy 不识别 bean 和其他类型的对象的区别,它仅仅依赖相应的 getter 和 setter 方法是否可用。我们可以通过一个实例对象的 getProperties 方法和 properties 属性来获取到实例对象属性的 map (key 为属性名称,value 为属性值)列表,操作样例如下:

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

class SomeClass {

def someProperty

public someField

private somePrivateField

}

def obj = new SomeClass()

def store = []

obj.properties.each { property ->

store += property.key

store += property.value

}

assert store.contains(‘someProperty’)

assert store.contains(‘someField’) == false

assert store.contains(‘somePrivateField’) == false

assert store.contains(‘class’)

assert store.contains(‘metaClass’)

assert obj.properties.size() == 3

Groovy 支持通过赋值方式扩展属性,这个特性很像 javascript,具体如下:

def ex = new Expando()

assert null == ex.address

ex.address = ‘abc’

assert ‘abc’ == ex.address

ex.callback = {count -> return this.address * count}

assert ‘abcabc’ == ex.callback(2)

Groovy MOP 元程序编程


Groovy 元程序编程是指在运行时改变对象和类行为的系统能力。这些东西其实只用知道大概即可,目前可以不用深究。

元类 MetaClass 概念

Groovy 所有的对象都实现了 GroovyObject 接口,它就像我们提到过的其它类一样,声明在groovy.lang包中,GroovyObject 看起来有如下的格式:

//【工匠若水 加微信 yanbo373131686 联系我,关注微信公众号:码农每日一题 未经允许严禁转载 https://blog.csdn.net/yanbober】

public interface GroovyObject {

public Object invokeMethod(String name, Object args);

public Object getProperty(String property);

public void setProperty(String property, Object newValue);

public MetaClass getMetaClass();

public void setMetaClass(MetaClass metaClass);

}

在 groovy 中你的所有类都是通过 GroovyClassGenerator 来构建的,因此它们都实现了 GroovyObject 这个接口。如果你希望一个一般的 java 类也被作为一个 Groovy 类来组织,你必须实现 GroovyObject 接口,为了便利性,你可以扩展抽象类 GroovyObjectSupport 类,其提供了默认的实现。

GroovyObject 与 MetaClass 协作,MetaClass 是 Groovy 元概念的核心,它提供了一个 Groovy 类的所有的元数据,如可用的方法、属性列表,MetaClass 常用的接口方法如下:

Object invokeMethod(Object obj, String methodName, Object args)

Object invokeMethod(Object obj, String methodName, Object[] args)

Object invokeStaticMethod(Object obj, String methodName, Object[] args)

Object invokeConstructor(Object[] args)

上面这些方法进行真正的方法调用工作,使用 JAVA 反射 API 或者通过透明创建一个反射类,GroovyObject 的 invokeMethod 方法默认实现总是转到相应的 MetaClass 中,而 MetaClass 被存储在一个名称为 MetaClassRegistry 的中心存储器中,同时 groovy 也从 MetaClassRegistry 中获取 MetaClass。所以当 Groovy 处理方法调用的时候请想到下面这个图:

在这里插入图片描述

特别注意:MetaClassRegistry 类被设计为单例模式,不能被直接实现,在代码中可以使用 InvokerHelper 的一个工厂方法来引用到这个单例的注册中心。GroovyObject 引用到的 MetaClass 是 GroovyObject 在 MetaClassRegistry 中注册的类型,他是不需要相同,例如,一个特定的对象可以有一个特殊的 MetaClass(这个 MetaClass 可以与该对象类的其他对象的 MetaClass 不一样)。

方法调用和拦截

Groovy 生成 java 字节码,所以其每一个方法的处理都遵循下列机制之一:

  1. 类自己实现 invokeMethod 的方法(也许被代理到 MetaClass);

  2. 它自己的 MetaClass 通过getMetaClass().invokeMethod()进行调用;

  3. 在 MetaClassRegistry 中注册的该类型的 MetaClass;

Groovy 每个方法调用时都有自己复杂的决策流程,很多时候我们其实是不需要考虑这些的,只是说明白这些细节是有价值的,这样在复杂的情况下你总是可以正确的工作,它也为你在你的类中增加动态行为提供了各种可能。包括了下面的可能性:

  • 你能够使用 aspects 进行方法调用的拦截,如日志跟踪、应用安全限制,强制事务控制等。

  • 你能够中转调用别的方法,例如一个包装类能中转所有的方法调用到被包装的对象上(其实闭包就是这样做的,它将方法调用代理给它的 delegate)。

  • 可以假装执行一个方法,这样可以应用一些特殊逻辑,例如,一个 Html 类可以假装有一个方法 body,当调用 body 方法的时候执行print(‘body’)

Groovy 方法调用逻辑有多种方式来实现拦截、中转或者伪装方法:

  • 实现/覆盖在 GroovyObject 中的 invokeMethod 方法来伪装或者中转方法调用(意味着覆盖点方法操作符);

  • 实现/覆盖在 GroovyObject 中的 invokeMethod 方法,并且也实现 GroovyInterceptable 接口来增加方法的拦截调用代码;

  • 提供一个 MetaClass 的实现类,并且在目标 GroovyObject 对象上调用 setMetaClass;

  • 提供一个 MetaClass 的实现类,并且在 MetaClassRegistry 中为所有的目标类(Groovy 和 java 类)进行注册,这种方案通过 ProxyMetaClass 进行支持;

由此就解释了 Groovy 动态语言的精髓在此。

学习交流

群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

E3Ioml-1714045727079)]

群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值