Groovy笔记(六)之元编程

本文介绍了Groovy的元编程概念,包括元对象协议(MOP)、GroovyObject接口及其方法,如invokeMethod、getProperty等。重点讨论了ExpandoMetaClass的使用,如何动态添加和修改方法、属性、构造函数。同时提到了GroovyInterceptable接口以及类别(Categories)的运用,展示了Groovy如何扩展静态和非静态类的能力。
摘要由CSDN通过智能技术生成

元对象协议(MOP)

  1. 在java中使用反射可以在运行时探索程序的结果,类、方法、参数等。但是我们仍然局限于所创建的静态结果。无法在运行时修改一个对象的类型,或是让它动态获得行为。如果可以基于应用的动态状态或基于应用所接受的输入,动态地添加方法和行为,代码会变得更灵活,在groovy中元编程就提供了这一功能
  2. 元编程意味着编写能够操作程序的程序,包括操作程序自身。像Groovy这样的动态语言通过元对象协议(MOP:MetaObject Protocol)提供了这种能力。在Groovy中使用MOP可以动态调用方法,甚至在运行时合成类和方法。
  3. groovy对象是带有附加功能的java对象,在Groovy中,Groovy对象比编译好的java对象具有更多的动态行为。此外,对于java对象和Groovy对象上的方法调用,Groovy的处理方式也是不同的。
  4. POJO(java对象)、POGO(groovy编写的对象,扩展了java.lang.Object,同时也实现了groovy.lang.GroovyOBject接口)、Groovy拦截器是扩展了GroovyInterceptable的Groovy对象,具有方法拦截功能
  5. GroovyInterceptable是一个标记接口,对于实现了该接口的对象而言,其上的所有方法调用,不管是存在的还是不存在的,都会被它的invokeMethod()方法拦截。
  6. Groovy支持POJO和POGO进行元编程,对于POJO,groovy维护了MetaClass的一个MetaClassRegistry。POGO有一个其到MetaClass的直接引用。当我们调用一个方法时,Groovy会检查目标对象是一个POJO还是一个POGO,对于不同的对象类型,Groovy的方法处理是不同的。对于POJO,Groovy会去应用类的MetaClassregistry取它的MetaClass,并将方法调用委托给它。因此我们在它的MetaClass上定义的任何拦截器或方法,都优先于POJO原来的方法

7.对于POGO,Groovy会采取一些额外的步骤。如果对象实现了GroovyInterceptable接口,那么所有的调用都会被路由给它的invokeMethod(),类似AOP

GroovyObject接口

  1. groovy.lang.GroovyObject是Groovy中的主要接口,就像Object类是Java中的主要接口一样。GroovyObjectgroovy.lang.GroovyObjectSupport类中有一个默认实现,它负责将调用传递给groovy.lang.MetaClass对象。 GroovyObject源代码如下:

        public interface GroovyObject {
         
            Object invokeMethod(String name, Object args);
            Object getProperty(String propertyName);
            void setProperty(String propertyName, Object newValue);
            MetaClass getMetaClass();
            void setMetaClass(MetaClass metaClass);
        }
    

invokeMethod

  1. 当调用的方法不存在于Groovy对象上时,将调用此方法

        class Person {
         
            def run() {
         
                println "run"
            }
        
            /**
             * 当您调用的方法不存在于Groovy对象上时,将调用此方法
             */
            def invokeMethod(String name, Object args) {
         
                println "called invokeMethod $name $args"
            }
        }
        
        def person = new Person()
        
        //输出:run
        person.run()
        //输出:called invokeMethod eat []
        person.eat()
    

get/setProperty

  1. 对属性的每个读取访问都可以通过覆盖当前对象的getProperty()方法来拦截,覆盖setProperty()方法来拦截对属性的写访问权限:

        class User {
         
            def username = "jannal"
            def age = 10
            def idCard
        
            def getProperty(String name) {
         
                if (name != 'password')
                //将请求转发到getter以获取除password之外的所有属性。
                    return metaClass.getProperty(this, name)
                else
                    return '123456'
            }
        
            def getAddress(){
         
                return "Beijing"
            }
            //setProperty()方法来拦截对属性的写访问权限:
            void setProperty(String name, Object value) {
         
                this.@"$name" = '4574'
            }
        }
        
        def user = new User()
        //jannal
        println user.username
        //10
        println user.age
        //Beijing
        println user.address
        //123456
        println user.password
        user.idCard = "411522199111114578"
        //4574
        println user.idCard
    
    

get/setMetaClass

  1. 访问对象的metaClass或设置自己的MetaClass实现以更改默认拦截机制。 例如,您可以编写自己的MetaClass接口实现,并将其分配给对象,从而更改拦截机制:

        // getMetaclass
        someObject.metaClass
        
        // setMetaClass
        someObject.metaClass = new OwnMetaClassImplementation()
    

get/setAttribute

  1. 此功能与MetaClass实现相关。 在默认实现中,您可以访问字段而不调用它们的gettersetter

        class Customer {
         
            def username = "jannal"
            def age = 10
            def getUsername(){
         
                return "jannal2"
            }
            def setAge(def age){
         
                this.age = "100"
            }
        }
        def customer = new Customer()
        
        //jannal2
        println customer.username
        println customer.age
        //jannal
        println customer.metaClass.getAttribute(customer, 'username')
        //10
        println customer.metaClass.getAttribute(customer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值