Groovy语法(四):面向对象

一、groovy中类,接口等的定义和使用

类的定义与使用

//在idea中直接新建一个Groovy Class

/**
 * groovy中默认都是public,groovy类最终都会继承GroovyObject
 */
class Person {
    //默认生成get/set方法
    String name
    Integer age

    //方法也默认是public的,def表明方法的返回类型是Object的
    def increaseAge(Integer years) {
        this.age += years
    }
}


//在脚本文件中使用定义好的类

//没有定义构造方法,也可以在创建对象是传入初始值,可传可不传
def person = new Person(name: 'groovy', age: 6)
println "the name is $person.name,the age is $person.age"  //the name is groovy,the age is 6

person.increaseAge(5)

//无论使用.还是get/set最终都会调用get/set方法
println person.age //11

接口的定义与使用

/**
 * groovy中接口不允许定义非public类型的方法
 */
interface Action {
    void eat()

    void work()

    void sleep()
}


//与java中一致
class Person implements Action{
    //默认生成get/set方法
    String name
    Integer age

    //方法也默认是public的,def表明方法的返回类型是Object的
    def increaseAge(Integer years) {
        this.age += years
    }

    @Override
    void eat() {}

    @Override
    void work() {}

    @Override
    void sleep() {}
}

Trait的定义与使用

//Trait 和接口几乎一模一样,只不过trait可以给接口提供默认的实现,
//相当于java中接口的适配器模式,直接继承接口就需要实现该接口的所有方法,但是很多时候我们里面有很多方法使我们不需要的,这个时候就可以定义一个适配器实现这个接口,给我们不需要的方法提供一个默认实现,这样我们就可以只关注我们需要的方法了

trait DefaultAction {
    abstract void eat()

    void work() {
        println 'i can work'
    }

    abstract void sleep()
}

class Person2 implements DefaultAction {

    @Override
    void eat() {}

    @Override
    void sleep() {}
}

def person2 = new Person2()
person2.work() //i can work

二、 groovy中的元编程

什么是元编程?

简单的理解就是编写代码执行的时期,比如由编译执行的java,运行时执行的代码(java反射)
groovy中运行时执行时序图

在这里插入图片描述

class Person1 {
    def invokeMethod(String name, Object args) {
        return "the method is $name,the params is $args"
    }
}

class Person2 {
    def methodMissing(String name, Object args) {
        return "the method $name is missing"
    }
}


class Person3 {

    def invokeMethod(String name, Object args) {
        return "the method is ${name},the params is ${args}"
    }

    def methodMissing(String name, Object args) {
        return "the method ${name} is missing"
    }
}

Person1 person1 = new Person1()
Person2 person2 = new Person2()
Person3 person3 = new Person3()

println person1.cry() //the method is cry,the params is []
println person2.cry() //the method cry is missing
println person3.cry() //the method cry is missing

//可以看到符合运行时时序图,当调用一个类中不存在的方法时,若重写了invokeMethod方法或者methodMissing方法时,会调用该方法(methodMissing的优先级更高)

MetaClass
前面的示例说明了groovy的运行时执行时序,那么当中的MetaClass又是什么?
我们都知道在groovy中,所有的对象都实现了GroovyObject接口

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);
}

每个对象都有一个MetaClass,MetaClass是Groovy元概念的核心,它提供了一个Groovy类的所有的元数据,如可用的方法、属性列表等.

MetaClass的作用

为类在运行时动态的添加属性或者方法
1.添加属性

class Person1 {}

Person1 person1 = new Person1()
person1.metaClass.sex = 'male'
println person1.sex //输出结果:male
person1.sex = "female"
println "the new sex is $person1.sex"  //输出结果:the new sex is female

//可以看到 Person1中并没有sex这个属性,而我们通过metaClass动态的添加了一个sex属性,并且能够正确的输出和修改

2.添加方法

class Person1 {}

Person1 person1 = new Person1()
person1.metaClass.sex = 'male'
person1.metaClass.sexUpperCase = { -> sex.toUpperCase() }
println person1.sexUpperCase()  //输出结果:MALE

3.添加静态方法

class Person {
    def name
    def age
}

//添加静态方法
Person.metaClass.static.createPerson = { String name, int age -> new Person(name: name, age: age) }

def person = Person.createPerson("groovy",6)
println person.name //输出结果:groovy

使用场景
使用每个类的MetaClass可以不修改任何类本身的代码,不通过继承类来扩展方法来动态的添加属性和方法。比如使用第三方库的时候,想要修改某些类,而类又是final的,即可通过MetaClass动态的注入属性和方法变相的达到修改的目的

ExpandoMetaClass.enableGlobally()
在一个脚本中动态注入的属性和方法,在其它脚本是不能直接使用的,想要使用需要在该脚本中重新注入。这是比较繁琐的,比如我们想要对String类型进行某一些操作,能不能为String注入方法,全局都能使用呢?答案是能,通过ExpandoMetaClass.enableGlobally()

//定义一个Person class
class Person {
    String name
    Integer age
}

//定义一个程序管理类 Application class
class Application {
    static void init() {
        //让注入的方法全局生效
        ExpandoMetaClass.enableGlobally()
        //注入一个静态方法(假设这里是为第三方类库注入了我们需要的方法)
        Person.metaClass.static.createPerson = { String name, Integer age -> new Person(name: name, age: age) }
    }
}

//定义另外一个类PersonManager class,在该类中使用Application class中为Person类注入的方法
class PersonManager {
    static Person createPerson(String name, Integer age) {
        //在另外一个脚本中使用注入的方法
        return Person.createPerson(name, age)
    }
}

//新的入口类 Entry class验证ExpandoMetaClass.enableGlobally()之后注入的方法可以全局调用
class Entry {
    static void main(String[] args) {
        println '程序开始...'
        Application.init() //注入
        Person p = PersonManager.createPerson('groovy', 6)
        println "the name is $p.name,the age is $p.age"

        //输出结果:
        /**
         * 程序开始...
         * the name is groovy,the age is 6
         */
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值