Groovy是一种基于Java虚拟机(JVM)的动态开发语言,旨在扩展Java语法,提供更简洁、灵活和易于使用的编码方式。
本文是在会一定java语言开发的基础上进行的对比入门学习记录。
def calculator = { operation, a, b ->
switch (operation) {
case "+": return a + b
case "-": return a - b
case "*": return a * b
case "/": return a / b
default: throw new IllegalArgumentException("Unknown operation")
}
}
println calculator("+", 5, 3)
与java基本相同,文件后缀为.groovy,示例:
class Datapatch extends BaseModel {
String patchId
Date createdAt
Date updatedAt
DatapatchDetails details
@Override
String getPK() {
return patchId
}
@Override
void setPK(String pk) {
patchId = pk
}
}
(1) jdk
(2) groovy sdk
groovy除了可以使用所有java语言的变量声明方式,还可以用def
来声明,def声明变量不用指定类型,访问权限默认为public
def s1 = "test"
def i1 = 123
def f1 = 12.1f
def c1 = 'c'
int a = 10
使用 返回类型
或 def
关键字 定义,方法可以接收任意数量的参数,这些参数可以不申明类型, 如果不提供可见性修饰符,则该方法为 public
。def
也可以用来声明函数。
//def定义方法 不声明返回类型和参数类型
def func1(name) {
//$占位符插值
println "$name"
}
//不声明返回类型,声明参数类型
def func2(int i, int b) {
return i + b
}
//返回类型声明方法,与java相同的方式
int func3(int a){
return a + 1
}
//可以在方法上指定默认值
def func4(word = "Hello ", name) {
println word + name
}
//调用的时候就可以不用传这个参数,如果传了就覆盖
func4("groovy")//输出 Hello groovy
//省略分号,类型,return
def func5(a,b,c) {
a,b,c //最后一行表达式的值会return
}
//省略 方法括号
def number = func5 a,b,c
//命名参数方法,用Map作为唯一参数
def foo(Map args){
println args.name
}
foo(name:'test',code:1)
○ 语句后面的分号
○ 调用方法的括号
○ 参数类型
○ return,方法最后一行的表达式结果默认return
○ 类、属性和方法的访问修饰符,省略默认为pblic,java省略默认是protected
与java类似,只不过省略public修饰符
● 默认类的修饰符为public,所有class及方法都是public
● 没有可见性修饰符的字段默认为类的属性,会自动生成对应的setter和getter方法。
● 类不需要与它的源文件有相同的名称,但还是建议采用相同的名称。
● 所有类 都继承自 GroovyObject
class Test{
//会自动对没有访问修饰符(默认是public)生产getter、setter
String name
int num
//创建对象方式四和五 需要声明构造方法
TestClass(name, age) {
this.name = name
this.age = age
}
//静态内部类
static class StaticInnerClass{
}
//非静态内部类
class InnerClass {
}
}
//创建对象方式一:与java相同
Test test1 = new Test()
test1.name = "测试1"
//创建对象方式二:当一个类没有构造方法的时候,其默认有一个命名参数构造方法
Test test2 = new Test(name:"测试2",num:10)
//创建对象方式三:with是一种特殊的用于减少重复代码的方式
Test test3 = new Test()
test3.with{
name = "测试3"
age = 20
}
//创建对象方式四:需要先有构造方法
def test4 = ["测试4",30] as Test
//创建对象方式五:需要先有构造方法
Test test5 = ["测试5",40]
//创建静态内部类
def staticInner = new StaticInnerClass()
//创建非静态内部类
Test test = new Test()
def inner = new InnerClass(test)
除了支持java的foreach和for i 形式,groovy还支持for in loop形式,支持遍历范围、列表、Map、数组和字符串等多种类型
println "for in loop range"
for ( i in 0..3 ) {
println i
}
println "for in loop array"
for ( i in [0, 1, 2, 3] ) {
println i
}
println "for in loop map"
def map = ['a':1, 'b':2, 'c':3]
for ( v in map.values() ) {
println v
}
groovy独有,GString是可变的,GString和String即使有相同的字面量,它们的hashCodes的值也可能不同,因此应该避免使用GString作为Map的key
//通过占位符插值的字符串是可变的,所以这种字符串类型就是GString
String s1 = "123"
GString string = "$s1"
println(string.hashCode())
String s2 = "123"
println(s2.hashCode())
String s3 = "123"
println(s3.hashCode())
//输出 48727 48690 48690
//单引号字符串,原样输出不可变,不支持插值和转义
def s1 = 'Single-quoted strings'
//双引号字符串,支持插值和转义
def ss = "111"
def s1 = "Double-quoted strings $ss"
//三引号字符串,常用于多行文本,支持插值和转义
def s1 = """Triple-quoted strings
This is second line"""
List:默认实现类ArrayList,可以直接使用[]声明一个lsit
//定义list
//groovy方式
def list1 = [1,2,3]
def list2 = []
//java方式
def list3 = new ArrayList()
//取值
//java方式
println list1.get(0)
//groovy方式
println list1[-1]
println list1.getAt(-2)
//添加值
list1 << 4
list1.leftShift(5)
list1 += 6
list1.plus 7
//插入指定位置
list1[1] = 21
list1.add(1,'e')
//插入另一个列表所有值
list1.addAll(1,[11,22])
//这种方式第一个值必须是list
list += [1,2] + 12 + 13 + [11,22]
//删除值
//删除所有值等于1的值
list1 -= 1
list1.remove 1
//遍历
list1.foreach{
//it是对应当前元素的隐式参数
println it
}
//带索引遍历
list1.eachWithIndex { it,idx->
println "value:$it,index:$idx"
}
//过滤使用的一些方法
find/findAll/findIndexOf/indexOf/every/any/groupBy
//常用方法collect,用来转换列表元素
def numbers = [1, 2, 3, 4, 5]
def squaredNumbers = numbers.collect { it * it }
println "Squared numbers: $squaredNumbers"
// 输出 Squared numbers: [1, 4, 9, 16, 25]
Map:直接使用[:]声明,默认的实现类为java.util.LinkedHashMap
def key = 'name'
//key 就是 "key"
def person = [key: '耗子尾汁']
//用括号表示传递一个变量,key='name'
person = [(key): '耗子尾汁']
//生成空map
def m = new HashMap()
def map = [:]
//只有一个参数或没有参数,形参可以不写
def func1 = {print it}
func1.call("test")
//多个参数则要显示定义
def func2 = {name,age ->{ println "name:$name,age:$age"}}
func2.call("test1",10)
Trait
具有Java Interface和抽象类的双重特征,介于java的接口和抽象类之间的,主要用来解决多重继承需求,在使用上:
● 可以定义属性,非final类型的,可以修改
● 像java-interface-default方法一样,有具体实现的方法
● 没有具体实现的方法必须用abstract
修饰为抽象方法
● 可以使用extends
、implement
来继承trait类
● 当不同的Trait
定义了相同的field
或者method
时, 将它们同时implements
的时候,后面的会覆盖前面的。比如 class A implements B,C ,那么C的field和method会覆盖B的
trait TestInterface {
String name
abstract void method1()
default String method2(){
name = "cccc"
return name
}
}
//实现类
class TestInterfaceImpl implements TestInterface {
@Override
void method1() {
System.out.println(this.method2());
}
static void main(String[] args) {
TestInterface t = new TestInterfaceImpl()
t.method1()
}
}
元编程是指在运行时创建、修改或操纵程序的能力。在代码执行过程中对程序进行自省和改变,从而实现更高级别的抽象和灵活性。
● 动态性:元编程使得在运行时创建、修改或删除类、对象、方法等成为可能。这种动态性使得我们可以根据运行时的情况来改变程序的行为,从而增强了程序的灵活性。
● 简化重复工作:通过使用元编程,我们可以编写更少的代码来实现相同的功能。通过动态地生成代码、修改代码或使用模板,我们可以避免冗长、重复的代码并提高开发效率。
● 领域特定语言(DSL):元编程使得创建领域特定语言成为可能。通过定义自己的语法和语义,我们可以为特定领域提供更易于理解和使用的接口。
● 框架扩展:许多开源框架都使用元编程来实现其内部机制。通过利用元编程能力,我们可以扩展这些框架的功能,满足我们特定的需求。
简单来说就是运行时期的一个策略。例如调用一个对象的某一个方法,如果这个方法不存在,编译器也不会报错,而是通过一系列的查找最终确定是调用还是抛出异常,下面就是简化后的流程:
现在有一个类结构如下:
package com.alvin.learn.test
class TestClass {
String name
Integer age
}
//TestClass本来没有code属性,动态添加一个
TestClass.metaClass.code = 10
def test = new TestClass()
println test.code
//可以正常修改
test.code = 2
println test.code
//输出 10 2
def test = new TestClass()
//1、现在类里面没有testMethod方法,所以执行会报 找不到此方法
test.testMethod("this is args")
//2、在TestClass 里面重写 invokeMethod方法
def invokeMethod(String name,Object args){
println("调用了invokeMethod,name:$name,args:$args")
}
//3、再次执行1处的调用,会打印
//调用了invokeMethod,name:testMethod,args:[this is args]
//4、在TestClass 里面重写 methodMissing方法
def methodMissing(String name,Object args){
println("调用了imethodMissing,name:$name,args:$args")
}
//5、再次执行1处的调用,会打印
//调用了imethodMissing,name:testMethod,args:t[this is args]
//6、动态创建方法
TestClass.metaClass.testMethod = {
println it
}
def test = new TestClass()
test.testMethod("this is args")
//打印 this is args
//7、动态添加静态方法
TestClass.metaClass.static.testStaticMethod = {
println 'this is a new static method'
}
TestClass.testStaticMethod()
//打印 this is a new static method
以上使用都是临时的,在别的类中使用添加的方法需要重新注入,以下使全局使用示例。
class TestManager {
static TestClass createTest(String name, int age) {
//调用不存在的方法
return TestClass.createTest(name, age)
}
}
class ApplicationManager {
static void init() {
//设置全局
ExpandoMetaClass.enableGlobally()
//创建 Person 静态方法
TestClass.metaClass.static.createTest = {
String name, Integer age ->
return new TestClass(name: name, age: age)
}
}
}
class Main {
public static void main(String[] args) {
println '应用程序正在启动'
//初始化
ApplicationManager.init()
println '应用程序初始化完成'
def test = TestManager.createTest("张三", 20)
println test.name + "----" + test.age
}
}
// 创建一个新的类
def myClass = this.class.classLoader.parseClass("""
class MyDynamicClass {
String name
MyDynamicClass(String name) {
this.name = name
}
}
""")
// 使用MetaClass为类添加方法
MyDynamicClass.metaClass.sayHello = { ->
"Hello, my name is ${delegate.name}"
}
// 实例化对象并调用新方法
def obj = new MyDynamicClass('Groovy')
println obj.sayHello()