groovy动态特性
动态/静态类型语言
- 动态类型语言
动态类型语言是指在运行期间才去做数据类型检查的语言,也就是说,在用动态类型的语言编程时,可以不用给变量指定数据类型,该语言会在你第一次赋值给变量时,在内部将数据类型记录下来。 - 静态类型语言
它的数据类型是在编译其间检查的,也就是说在写程序时要声明所有变量的数据类型,C/C++/Java是静态类型语言的典型代表
Groovy的动态特性
- 使用def定义变量,类型由运行时对其赋值的类型类确定。
- Java中要使用继承才能实现多态,而Groovy轻而易举。
- 优势:使用时非常灵活!
- 缺点:编译时不会检查类型,运行时报错,需要更加注重细节。
- 可以通过@TypeChecked去检查,但是并不强大,而且会损失动态语言特性
-
可以使用MOP进行元编程。
image.png
class Person{
def name="peakmain"
void setName(String name) {
println("setName(String name)")
this.name = name
}
void setName(Object name) {
println("setName(Object name)")
this.name = name
}
}
def person=new Person()
Object name="treasure"
person.name=name
我们会发现name最后一次赋值的类型是String,所以打印的结果是setName(String name)
元编程
- java可以通过反射,在运行时动态的获取类的属性,方法等信息,然后通过反射调用。但是没法直接向内中添加属性、方法和行为。
- MOP:元对象协议
- Groovy直接可以使用MOP进行元编程,我们可以基于应用当前的状态,动态的添加或者改变类的方法和行为。
MOP方法拦截
- 实现GroovyInterceptable接口,重写invokeMethod来进行拦截。
class Person implements GroovyInterceptable {
def func() {
println("I am func ")
}
@Override
Object invokeMethod(String name, Object args) {
System.out.println("$name invokeMethod")
System.out.println("$metaClass invokeMethod")
//respondsTo(name)//判断是否存在
if(metaClass.invokeMethod(this,"respondsTo",name,args)){
System.out.println("$name 方法存在")
metaClass.invokeMethod(this,name,args)
}
}
}
new Person().func()
- 使用MetaClass拦截方法,覆盖invokeMethod方法。
- 使用类的MetaClass,针对的是class对象,所有实例都会被影响。
- 使用具体实例的MetaClass,只影响当前对象实例
class Person {
def func() {
println("I am func ")
}
}
def person = new Person()
//只拦截某个对象的某一个方法
person.metaClass.func = {
println("I am metaClass func ")
}
//多个方法
person.metaClass.invokeMethod = {
String name, Object args ->
println("I am $name 被拦截了 ")
}
person.func()
toString的拦截
String.metaClass.invokeMethod={
String name,Object args->
MetaMethod metaMethod=delegate.metaClass.getMetaMethod(name)
if(metaMethod!=null&&name=="toString"){
"peakmain"
}
}
println "hello".toString()
MOP方法注入
- 方法注入:编写代码时知道想要添加到一个或多个类中的方法的名字。利用方法注入,可以动态地向类中添加行为。也可以向任意数目的类中注入一组实现某一特定功能的可复用方法,类似工具函数。有以下几种方式:
- 1、使用metaClass注入方法
class Person {
def func() {
println("I am Person func ")
}
}
def person=new Person()
person.metaClass.newFunc={
println("I am metaClass newFunc ")
}
person.newFunc()
- 2、使用ExpandoMetaClass注入方法
直接使用类或实例的MetaClass注入方法,实际上最终操作的类型是ExpandoMetaClass。手动创建ExpandoMetaClass来进行注入
def expandoMetaClass = new ExpandoMetaClass(Person)
expandoMetaClass.func1 = {
println("I am expandoMetaClass func1 ")
}
expandoMetaClass.initialize()
Person.metaClass=expandoMetaClass
new Person().func1()
- 3、使用分类注入方法
写法一
class Utils{
static def isEmpty(String name){
println("isEmpty")
name.length()==0||name==null
}
}
use(Utils){
"".isEmpty()
}
写法二
@Category(String)
class Utils{
def isEmpty(){
println("isEmpty")
this.length()==0||this==null
}
}
use(Utils){
"".isEmpty()
}
MOP方法合成
- 方法合成:想在调用时动态地确定方法的行为。Groovy的invokeMethod()、methodMissing()和GroovyInterceptable对于方法合成非常有用
- 使用methodMissing()合成方法。
- 使用ExpandoMetaClass合成方法
MOP方法委托
- 使用Expando动态生成动态类
- 使用methodMissing实现方法委托
def e=new Expando(name:"peakmain",func:{
println("func")
})
e.name="haha"
println(e.name)
运算符重载
简单案例:重载+
Integer.metaClass.plus = {
int a ->
"$delegate+$a"
}
println(1+2)
方法 | 重载 |
---|---|
a + b | a.plus(b) |
a – b | a.minus(b) |
a * b | a.multiply(b) |
a ** b | a.power(b) |
a / b | a.div(b) |
a % b | a.mod(b) |
a & b | a.and(b) |
a ^ b | a.xor(b) |
a++ or ++a | a.next() |
a– or –a | a.previous() |
a[b] | a.getAt(b) |
a[b] = c | a.putAt(b, c) |
a << b | a.leftShift(b) |
a >> b | a.rightShift(b) |
~a | a.bitwiseNegate() |
-a | a.negative() |
网友评论