美文网首页
Gradle基础到进阶——Groovy动态特性和元编程(二)

Gradle基础到进阶——Groovy动态特性和元编程(二)

作者: Peakmain | 来源:发表于2021-08-05 12:00 被阅读0次

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()

相关文章

网友评论

      本文标题:Gradle基础到进阶——Groovy动态特性和元编程(二)

      本文链接:https://www.haomeiwen.com/subject/nffpvltx.html