Groovy面向?qū)ο?/h1>
一、groovy中類腹尖,接口等的定義和使用
- 類的定義與使用
//在idea中直接新建一個(gè)Groovy Class
/**
* groovy中默認(rèn)都是public狮荔,groovy類最終都會(huì)繼承GroovyObject
*/
class Person {
//默認(rèn)生成get/set方法
String name
Integer age
//方法也默認(rèn)是public的,def表明方法的返回類型是Object的
def increaseAge(Integer years) {
this.age += years
}
}
//在腳本文件中使用定義好的類
//沒(méi)有定義構(gòu)造方法贫贝,也可以在創(chuàng)建對(duì)象是傳入初始值秉犹,可傳可不傳
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)
//無(wú)論使用.還是get/set最終都會(huì)調(diào)用get/set方法
println person.age //11
- 接口的定義與使用
/**
* groovy中接口不允許定義非public類型的方法
*/
interface Action {
void eat()
void work()
void sleep()
}
//與java中一致
class Person implements Action{
//默認(rèn)生成get/set方法
String name
Integer age
//方法也默認(rèn)是public的,def表明方法的返回類型是Object的
def increaseAge(Integer years) {
this.age += years
}
@Override
void eat() {}
@Override
void work() {}
@Override
void sleep() {}
}
- Trait的定義與使用
//Trait 和接口幾乎一模一樣稚晚,只不過(guò)trait可以給接口提供默認(rèn)的實(shí)現(xiàn)崇堵,
//相當(dāng)于java中接口的適配器模式,直接繼承接口就需要實(shí)現(xiàn)該接口的所有方法客燕,但是很多時(shí)候我們里面有很多方法使我們不需要的鸳劳,這個(gè)時(shí)候就可以定義一個(gè)適配器實(shí)現(xiàn)這個(gè)接口,給我們不需要的方法提供一個(gè)默認(rèn)實(shí)現(xiàn)也搓,這樣我們就可以只關(guān)注我們需要的方法了
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中的元編程
- 什么是元編程?
簡(jiǎn)單的理解就是編寫代碼執(zhí)行的時(shí)期涵紊,比如由編譯執(zhí)行的java,運(yùn)行時(shí)執(zhí)行的代碼(java反射)
-
groovy中運(yùn)行時(shí)執(zhí)行時(shí)序圖
image.png
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
//可以看到符合運(yùn)行時(shí)時(shí)序圖,當(dāng)調(diào)用一個(gè)類中不存在的方法時(shí),若重寫了invokeMethod方法或者methodMissing方法時(shí)幔摸,會(huì)調(diào)用該方法(methodMissing的優(yōu)先級(jí)更高)
- MetaClass
前面的示例說(shuō)明了groovy的運(yùn)行時(shí)執(zhí)行時(shí)序摸柄,那么當(dāng)中的MetaClass又是什么?
我們都知道在groovy中既忆,所有的對(duì)象都實(shí)現(xiàn)了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);
}
//在idea中直接新建一個(gè)Groovy Class
/**
* groovy中默認(rèn)都是public狮荔,groovy類最終都會(huì)繼承GroovyObject
*/
class Person {
//默認(rèn)生成get/set方法
String name
Integer age
//方法也默認(rèn)是public的,def表明方法的返回類型是Object的
def increaseAge(Integer years) {
this.age += years
}
}
//在腳本文件中使用定義好的類
//沒(méi)有定義構(gòu)造方法贫贝,也可以在創(chuàng)建對(duì)象是傳入初始值秉犹,可傳可不傳
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)
//無(wú)論使用.還是get/set最終都會(huì)調(diào)用get/set方法
println person.age //11
/**
* groovy中接口不允許定義非public類型的方法
*/
interface Action {
void eat()
void work()
void sleep()
}
//與java中一致
class Person implements Action{
//默認(rèn)生成get/set方法
String name
Integer age
//方法也默認(rèn)是public的,def表明方法的返回類型是Object的
def increaseAge(Integer years) {
this.age += years
}
@Override
void eat() {}
@Override
void work() {}
@Override
void sleep() {}
}
//Trait 和接口幾乎一模一樣稚晚,只不過(guò)trait可以給接口提供默認(rèn)的實(shí)現(xiàn)崇堵,
//相當(dāng)于java中接口的適配器模式,直接繼承接口就需要實(shí)現(xiàn)該接口的所有方法客燕,但是很多時(shí)候我們里面有很多方法使我們不需要的鸳劳,這個(gè)時(shí)候就可以定義一個(gè)適配器實(shí)現(xiàn)這個(gè)接口,給我們不需要的方法提供一個(gè)默認(rèn)實(shí)現(xiàn)也搓,這樣我們就可以只關(guān)注我們需要的方法了
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
簡(jiǎn)單的理解就是編寫代碼執(zhí)行的時(shí)期涵紊,比如由編譯執(zhí)行的java,運(yùn)行時(shí)執(zhí)行的代碼(java反射)
groovy中運(yùn)行時(shí)執(zhí)行時(shí)序圖
image.png
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
//可以看到符合運(yùn)行時(shí)時(shí)序圖,當(dāng)調(diào)用一個(gè)類中不存在的方法時(shí),若重寫了invokeMethod方法或者methodMissing方法時(shí)幔摸,會(huì)調(diào)用該方法(methodMissing的優(yōu)先級(jí)更高)
前面的示例說(shuō)明了groovy的運(yùn)行時(shí)執(zhí)行時(shí)序摸柄,那么當(dāng)中的MetaClass又是什么?
我們都知道在groovy中既忆,所有的對(duì)象都實(shí)現(xiàn)了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);
}
每個(gè)對(duì)象都有一個(gè)MetaClass驱负,MetaClass是Groovy元概念的核心,它提供了一個(gè)Groovy類的所有的元數(shù)據(jù)患雇,如可用的方法跃脊、屬性列表等.
- MetaClass的作用
為類在運(yùn)行時(shí)動(dòng)態(tài)的添加屬性或者方法
1.添加屬性
class Person1 {}
Person1 person1 = new Person1()
person1.metaClass.sex = 'male'
println person1.sex //輸出結(jié)果:male
person1.sex = "female"
println "the new sex is $person1.sex" //輸出結(jié)果:the new sex is female
//可以看到 Person1中并沒(méi)有sex這個(gè)屬性,而我們通過(guò)metaClass動(dòng)態(tài)的添加了一個(gè)sex屬性苛吱,并且能夠正確的輸出和修改
2.添加方法
class Person1 {}
Person1 person1 = new Person1()
person1.metaClass.sex = 'male'
person1.metaClass.sexUpperCase = { -> sex.toUpperCase() }
println person1.sexUpperCase() //輸出結(jié)果:MALE
3.添加靜態(tài)方法
class Person {
def name
def age
}
//添加靜態(tài)方法
Person.metaClass.static.createPerson = { String name, int age -> new Person(name: name, age: age) }
def person = Person.createPerson("groovy",6)
println person.name //輸出結(jié)果:groovy
使用場(chǎng)景
使用每個(gè)類的MetaClass可以不修改任何類本身的代碼酪术,不通過(guò)繼承類來(lái)擴(kuò)展方法來(lái)動(dòng)態(tài)的添加屬性和方法。比如使用第三方庫(kù)的時(shí)候又谋,想要修改某些類拼缝,而類又是final的,即可通過(guò)MetaClass動(dòng)態(tài)的注入屬性和方法變相的達(dá)到修改的目的ExpandoMetaClass.enableGlobally()
在一個(gè)腳本中動(dòng)態(tài)注入的屬性和方法彰亥,在其它腳本是不能直接使用的咧七,想要使用需要在該腳本中重新注入。這是比較繁瑣的任斋,比如我們想要對(duì)String類型進(jìn)行某一些操作继阻,能不能為String注入方法,全局都能使用呢废酷?答案是能瘟檩,通過(guò)ExpandoMetaClass.enableGlobally()
//定義一個(gè)Person class
class Person {
String name
Integer age
}
//定義一個(gè)程序管理類 Application class
class Application {
static void init() {
//讓注入的方法全局生效
ExpandoMetaClass.enableGlobally()
//注入一個(gè)靜態(tài)方法(假設(shè)這里是為第三方類庫(kù)注入了我們需要的方法)
Person.metaClass.static.createPerson = { String name, Integer age -> new Person(name: name, age: age) }
}
}
//定義另外一個(gè)類PersonManager class,在該類中使用Application class中為Person類注入的方法
class PersonManager {
static Person createPerson(String name, Integer age) {
//在另外一個(gè)腳本中使用注入的方法
return Person.createPerson(name, age)
}
}
//新的入口類 Entry class驗(yàn)證ExpandoMetaClass.enableGlobally()之后注入的方法可以全局調(diào)用
class Entry {
static void main(String[] args) {
println '程序開(kāi)始...'
Application.init() //注入
Person p = PersonManager.createPerson('groovy', 6)
println "the name is $p.name,the age is $p.age"
//輸出結(jié)果:
/**
* 程序開(kāi)始...
* the name is groovy,the age is 6
*/
}
}