Groovy 快速入门

本文介绍了Groovy,一种在Java平台上动态、面向对象的编程语言,涵盖其基本特点、动态类型、闭包、语法特性、文件I/O操作,以及与Java的无缝集成。通过实例演示了如何使用Groovy简化编程和提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


在这里插入图片描述

Groovy 语言

概述

简介

Groovy是用于Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。

Groovy是JVM的一个替代语言(替代是指可以用 Groovy 在Java平台上进行 Java 编程),使用方式基本与使用 Java代码的方式相同,该语言特别适合与Spring的动态语言支持一起使用,设计时充分考虑了Java集成,这使 Groovy 与 Java 代码的互操作很容易。(注意:不是指Groovy替代java,而是指Groovy和java很好的结合编程。

基本特点

  • 构建在强大的Java语言之上 并 添加了从Python,Ruby和Smalltalk等语言中学到的 诸多特征,例如动态类型转换、闭包和元编程(metaprogramming)支持。
  • 为Java开发者提供了 现代最流行的编程语言特性,而且学习成本很低(几乎为零)。
  • 支持DSL(Domain Specific Languages领域定义语言)和其它简洁的语法,让代码变得易于阅读和维护。
  • 受检查类型异常(Checked Exception)也可以不用捕获。
  • Groovy拥有处理原生类型,面向对象以及一个Ant DSL,使得创建Shell Scripts变得非常简单。
  • 在开发Web,GUI,数据库或控制台程序时 通过 减少框架性代码 大大提高了开发者的效率。
  • 支持单元测试和模拟(对象),可以 简化测试。
  • 无缝集成 所有已经存在的 Java对象和类库。
  • 直接编译成Java字节码,这样可以在任何使用Java的地方 使用Groovy。
  • 支持函数式编程,不需要main函数。
  • 一些新的运算符。
  • 默认导入常用的包。
  • 断言不支持jvm的-ea参数进行开关。
  • 支持对对象进行布尔求值。
  • 类不支持default作用域,且默认作用域为public。
  • groovy中基本类型也是对象,可以直接调用对象的方法。

动态类型

类型对于变量,属性,方法,闭包的参数以及方法的返回类型都是可有可无的,都是在给变量赋值的时候才决定它的类型, 不同的类型会在后面用到,任何类型都可以被使用,即使是基本类型 (通过自动包装(autoboxing)). 当需要时,很多类型之间的转换都会自动发生,比如在这些类型之间的转换: 字符串(String),基本类型(如int) 和类型的包装类 (如Integer)之间,可以把不同的基本类型添加到同一数组(collections)中。

闭包

闭包就是可以使用参数的代码片段,每个闭包会被编译成继承groovy.lang.Closure类的类,这个类有一个叫call方法,通过该方法可以传递参数并调用这个闭包.它们可以访问并修改在闭包创建的范围内的变量,在闭包内创建的变量在闭包被调用的范围内同样可以被引用, 闭包可以保存在变量中并被作为参数传递到方法中。

语法

Groovy 语法与Java 语言的语法很相似,虽然 Groovy 的语法源于Smalltalk和Ruby这类语言的理念,但是可以将它想像成 Java 语言的一种更加简单、表达能力更强的变体。(在这点上,Ruby与 Groovy 不同,因为它的语法与 Java 语法差异很大。)

许多 Java 开发人员喜欢 Groovy 代码和 Java 代码的相似性。从学习的角度看,如果知道如何编写 Java 代码,那就已经了解 Groovy 了。Groovy 和 Java 语言的主要区别是:完成同样的任务所需的 Groovy 代码比 Java 代码更少。

Groovy类和java类一样,完全可以用标准java bean的语法定义一个Groovy类。但作为另一种语言,可以使用更Groovy的方式定义类,这样的好处是,可以少写一半以上的javabean代码。

  • 不需public修饰符

如前面所言,Groovy的默认访问修饰符就是public,如果Groovy类成员需要public修饰,则根本不用写它。

  • 不需要类型说明

同样前面也说过,Groovy也不关心变量和方法参数的具体类型。

  • 不需要getter/setter方法

在很多ide(如eclipse)早就可以为程序员自动产生getter/setter方法了,在Groovy中,不需要getter/setter方法–所有类成员(如果是默认的public)根本不用通过getter/setter方法引用它们(当然,如果一定要通过getter/setter方法访问成员属性,Groovy也提供了它们)。

  • 不需要构造函数

不再需要程序员声明任何构造函数,因为实际上只需要两个构造函数(1个不带参数的默认构造函数,1个只带一个map参数的构造函数–由于是map类型,通过这个参数可以构造对象时任意初始化它的成员变量)。

  • 不需要return

Groovy中,方法不需要return来返回值。

环境准备

java 项目中使用 Groovy 引入其依赖即可

<dependency>
    <groupId>org.apache.groovy</groupId>
    <artifactId>groovy</artifactId>
    <version>4.0.2</version>
</dependency>

基本语法

创建一个以 .groovy 为后缀的文件,我们可以在这文件中像开发java代码一样简单的去使用 groovy,并且 groovy 提供的语法更加简洁。

我们可以完全像开发 Java 代码一样去编写 Groovy,也可以根据 Groovy 的语法来简化编写。

第一个 Hello world 程序

class Example {
   static void main(String[] args) {
      // 使用 println 就可打印输出,并且类和方法默认就是public,可以不用写
      println('Hello World');
   }
}

运行

Hello World

Groovy 的导入语句

和 Java 一样,都是使用 Import 进行导入

import groovy.xml.MarkupBuilder 	// Import 进行导入需要的类
def xml = new MarkupBuilder() 		// def 就是动态类型,在Groovy可以不用指定具体的类型,就像js中的var一样

在编译的 Groovy 字节码文件中,Groovy 已经默认帮我们导入了一些jar包,这些 jar 包可以不用再显示的导入

import java.lang.* 
import java.util.* 
import java.io.* 
import java.net.* 

import groovy.lang.* 
import groovy.util.* 

import java.math.BigInteger 
import java.math.BigDecimal

Groovy 的注释

和 Java 一样,支持单行 // 和多行注释 /**/

// Using a simple println statement to print output to the console

/* This program is the first program
      This program shows how to display hello world */

Groovy 的分号

; 分号,可以用来区分不同的代码块。

在 Groovy 编写中可以,可以省略分号符

Groovy 的标识符

和 Java 一样,标识符就是变量名,声明规则和 Java 一样,可以以字母开头,美元或下划线。但不能以数字开头。

Groovy 的关键字

大部分关键字和 Java 中的用法一样

asassertbreakcase
catchclassconstcontinue
defdefaultdoelse
enumextendsfalseFinally
forgotoifimplements
importininstanceofinterface
newpullpackagereturn
superswitchthisthrow
throwstraittruetry
while

数据类型

Groovy 的内置数据类型和 Java 一样有8种。byte、short、int、long、float、double、char、boolean

字符串:String

并且都有其对应的封装类

变量

变量也和 Java 一样,除了使用基本数据类型和引用类型,还可以使用def动态数据类型来声明变量。

// 和java的区别就是多了,def动态类型
def a = 1; // 在编译时会自动转化为int
def a = 'aa';

运算符

大部分运算符和 Java 一样,如:算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符

与 Java 不同点在于,新增了 范围运算符

def range = 0..5 

范围运算符通过..来指定其开始和结束的范围。

上面示例就简单的定义了一个,从0到5的范围。

class Example { 
   static void main(String[] args) { 
      def range = 5..10; 	// 定义一个5~10的范围
      println(range); 	// 打印范围
      println(range.get(2)); 	// 取范围中是数据
   } 
}

运行

[5, 6, 7, 8, 9, 10] 
7

可以发现,范围变量,本质就是封装了一层数组。在操作时,通过其下标进行存取。

运算符优先级

运算符名称
++--+-预增/减(自增/减),一元加,一元减
* /乘法,除法,取模
+-加法,减法(二元)
==!=<=>等于,不等于,比较运算符
二进制/位运算符与
^二进制/位异或
``
逻辑非
&&逻辑与
`
=+=-=*=/=%=**=各种赋值运算符

循环

Groovy 中的循环和 Java 中一样,包含循环跳出和结束循环等

while、for、break、continue

不同之处

在 Java 中我们常常使用foreach来遍历

for(String str : strList){
    ...
}

而在 Groovy 中提供了for in语句,其使用方法和 Java 一样,只是关键字不同

for(def str in strList){
    println(str);
}

条件语句

Groovy 中的条件语句和 Java 中的一样,其关键字如下

if、else、switch

包括其嵌套使用等

方法

在 Groovy 中,方法的返回类型可以是 def 类型,而且在定义方法参数时,可以不必显示的定义参数的具体类型。

其方法修饰符默认为 public,可以添加其它修饰符,和 Java一样,默认 public 可以不用写

无参方法

def methodName() { 
   //Method code 
}

有参方法

def methodName(parameter1, parameter2, parameter3) { 
   // Method code goes here 
}

具体示例

class Example {
   static void sum(int a,int b) {
      int c = a+b;
      println(c);
   }  
	
   static void main(String[] args) {
      sum(10,5);
   } 
}

输出 15

默认参数值

在 Groovy 中,定义方法参数时,可以指定其参数的默认值,如果在调用此方法时有传入值,则使用传入值,否则使用默认值

class Example { 
   static void sum(int a,int b = 5) { 	// 参数b的默认值为5
      int c = a+b; 
      println(c); 
   } 
	
   static void main(String[] args) {
      sum(6); // 我们在调用时,只传入了一个参数
   } 
}

输出 11

因为参数 b 有默认值,所以我们在使用时,可以选择传或不传参数 b

如果调用时,传入参数 b,则在计算时,会使用我们传入的值

class Example {
   static void sum(int a,int b = 5) {
      int c = a+b;
      println(c);
   } 
	
   static void main(String[] args) {
      sum(6,6);	// 传入参数b
   } 
}

输出 12

无参调用

class test {

    static void main(String[] args){
        sun()	// 无参调用
    }

    static void sun(a = 1,b = 2){
        println(a+b)
    }
}

输出 3

**注意:**如果方法没有默认值,在调用时,必须传入参数。

文件 I/O

Groovy 的IO除了使用 Java 的 API 以外,还提供了辅助类供我们使用

标准 Java 类

  • java.io.File
  • java.io.InputStream
  • java.io.OutputStream
  • java.io.Reader
  • java.io.Writer

读取文件

可以使用 Groovy 提供的 File 类中的 eachLine 方法来快速读取文本文件的每一行

import java.io.File 
class Example { 
   static void main(String[] args) { 
      new File("E:/Example.txt").eachLine {  
         line -> println "line : $line" 
      } 
   } 
}

如果想将文件的整个内容作为字符串获取,可以使用文件类的 text 属性

class Example { 
   static void main(String[] args) { 
      File file = new File("E:/Example.txt") 
      println file.text 
   } 
}

写入文件

在写入文件时,也提供了对应的写入辅助

import java.io.File 
class Example { 
   static void main(String[] args) { 
      new File('E:/','Example.txt').withWriter('utf-8') { 
         writer -> writer.writeLine 'Hello World' 
      }  
   } 
}

获取文件大小

可以通过 File 类的 length 属性进行获取

class Example {
   static void main(String[] args) {
      File file = new File("E:/Example.txt")
      println "The file ${file.absolutePath} has ${file.length()} bytes"
   } 
}

测试文件是否为目录

class Example { 
   static void main(String[] args) { 
      def file = new File('E:/') 
      println "File? ${file.isFile()}" 
      println "Directory? ${file.isDirectory()}" 
   } 
}

// 输出
File? 
Directory? True

创建目录

class Example {
   static void main(String[] args) {
      def file = new File('E:/Directory')
      file.mkdir()	// 如果文件夹不存在则创建
   } 
}

删除文件

class Example {
   static void main(String[] args) {
      def file = new File('E:/Example.txt')
      file.delete()
   } 
}

复制文件

class Example {
   static void main(String[] args) {
      def src = new File("E:/Example.txt")
      def dst = new File("E:/Example1.txt")
      dst << src.text
   } 
}

复制文件使用 << 特殊符号即可进行复制,

代码解释:将创建文件 Example1.txt,并将文件 Example.txt 的所有内容复制到此文件。

获取目录所在驱动器

class Example { 
   static void main(String[] args) { 
      def rootFiles = new File("test").listRoots() // 获取驱动器列表
      rootFiles.each { 
         file -> println file.absolutePath // 遍历并打印
      }
   }
}

列出指定目录下的文件

class Example {
   static void main(String[] args) {
      new File("E:/Temp").eachFile() {  // 使用 eachFile 获取目录下的所有文件
         file->println file.getAbsolutePath()
      }
   } 
}

列出指定目录下的所有文件,包括递归处理子目录文件

class Example { 
   static void main(String[] args) {
      new File("E:/temp").eachFileRecurse() {	// 使用 eachFileRecurse 方法
         file -> println file.getAbsolutePath()
      }
   }
} 

字符串

Groovy中的字符串可以用单引号('),双引号(“)或三引号(" ')括起来。

class test {

    static void main(String[] args){
        String a = 'Hello Single';
        String b = "Hello Double";
        String c = "'Hello Triple' + 'Multiple lines'";	// 注意如果单引号在外则不是字符串拼接

        println(a);
        println(b);
        println(c);
    }
}

输出

Hello Single
Hello Double
'Hello TripleMultiple lines'

也可以使用占位符去拼接字符串

name = 'Wangfang'
age = '18'

// 占位符拼接的用法
print("my name is ${name},my age is ${age}.")

字符串索引

可以直接使用字符下标获取字符串中的字符

class Example { 
   static void main(String[] args) { 
      String sample = "Hello world"; 
      println(sample[4]); // 打印第5个字符
		
      // 打印字符串最后一位字符
      println(sample[-1]); 
      println(sample[1..2]);// 打印索引 1 ~ 2 的字符 
      println(sample[4..2]);// 反向打印,从索引4到索引2
      
   } 
}

输出

o 
d 
el 
oll 

列表

Groovy 中的一个列表中的数据可以是任意类型。这 java 下集合列表有些不同,java 下的列表是同种类型的数据集合。

Groovy 列表可以嵌套列表。如 [1,2,[3,4,5],“aaa”]

Groovy 列表内置有反转方法 reverse()。调用 List.reverse() 可以实现列表反转。Groovy 列表内置有排序方法 sort()。调用 List.sort() 可以实现列表排序。

常用方法

添加

def list1 = [100, 101]
def list2 = [ 99,98,1]
println list2.plus(list1) //输出结果: [100, 101, 99, 98,1]
// list2.plus(list1) 也可以写成 list2 + list1

删除

def list1 = [12, 13]
def list2 = [11, 2, 33, 12, 13, 16]
println list2.minus(list1) //输出结果: [11, 2, 33, 16]
//list2.minus(list1) 也可以写成 list2 - list1

键值映射

在 Groovy 除了使用 Java 的Map集合,还可以显示的定义映射

['TopicName':'Lists','TopicName':'Maps'] //具有TopicName作为键的键值对的集合及其相应的值。
[:] // 空映射。

正则表达式

Groovy 中,使用正则表达式可以使用 ~ 符号来判断

'Groovy' =~ 'Groovy' 
'Groovy' =~ 'oo' 
'Groovy' ==~ 'Groovy' 
'Groovy' ==~ 'oo' 
'Groovy' =~ '∧G' 
'Groovy' =~ 'G$' 
'Groovy' =~ 'Gro*vy' 'Groovy' =~ 'Gro{2}vy'

traits 特征

在 Groovy 中可以定义用 traits 修饰的类,表示特征类,它可以看作是有默认实现和状态的接口

trait Marks {
   void DisplayMarks() {
      println("Display Marks");
   } 
}

我们可以使用 implement 关键字以类似于接口的方式实现 trait

trait Marks { 
   void DisplayMarks() {	// 特征里有一个实现方法
      println("Display Marks");
   } 
} 

class Student implements Marks { 	// 可以像实现接口一样实现 trait 类
   int StudentID
   int Marks1;
}

class Example {
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      st.Marks1 = 10; 
      println(st.DisplayMarks());
   } 
} 

实现接口

Traits 类可以实现接口

interface Total { 	//	接口
   void DisplayTotal() 
} 

trait Marks implements Total {	// trait实现接口
   void DisplayMarks() {
      println("Display Marks");
   }
	
   void DisplayTotal() {	// 实现接口的方法
      println("Display Total"); 
   } 
} 

class Student implements Marks { 	// 普通类实现trait类
   int StudentID
   int Marks1;  
} 

class Example {
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
      st.Marks1 = 10;
		
      println(st.DisplayMarks());
      println(st.DisplayTotal());
   } 
} 

属性

在 trait 类中也可以定义属性

interface Total {
    void DisplayTotal() 
} 
	
trait Marks implements Total {	//trait类
    int Marks1;

    void DisplayMarks() {
        this.Marks1 = 10;
        println(this.Marks1);
    }

    void DisplayTotal() {
        println("Display Total");
    } 
}

多重实现

trait Marks {
   void DisplayMarks() {
      println("Marks1");
   } 
} 

trait Total {
   void DisplayTotal() { 
      println("Total");
   } 
}  

class Student implements Marks,Total {	// 具体类可以实现多个 特征类
   int StudentID 
}  

class Example {
   static void main(String[] args) {
      Student st = new Student();
      st.StudentID = 1;
		
      println(st.DisplayMarks());
      println(st.DisplayTotal()); 
   } 
}

特征继承

特征类可以继承

trait Marks {
    void DisplayMarks() {
        println("Marks1");
    } 
} 

trait Total extends Marks {	//Total 继承 Marks
    void DisplayMarks() {
        println("Total");
    } 
}  

class Student implements Total {
    int StudentID 
}

class Example {
    static void main(String[] args) {
        Student st = new Student();
        st.StudentID = 1;
        println(st.DisplayMarks());
    } 
} 

闭包

Groovy 的闭包,就是一个匿名的代码块,并且可以作为参数

class Example {
   static void main(String[] args) {
      def clos = {println "Hello World"};	// 简单的闭包
      clos.call();
   } 
}

// 输出
Hello World

上面的例子中,使用{代码块}声明的被称为闭包,变量标识符可以通过 call 方法执行代码块

闭包中的形式参数

闭包代码块中,可以包含形式参数

class Example {
   static void main(String[] args) {
      def clos = {param -> println "Hello ${param}"};
      clos.call("World");
   } 
}

还可以使用下面这种方式来进行定义,可以得到相同的结果

class Example {
   static void main(String[] args) {
      def clos = {println "Hello ${it}"};
      clos.call("World");
   } 
}

it参数,是Groovy定义的关键字,它被称为隐式单个参数

闭包和变量

在闭包代码块中,我们还可以使用变量,通过${变量名}来使用

class Example {     
   static void main(String[] args) {
      def str1 = "Hello";
      def clos = {param -> println "${str1} ${param}"}
      clos.call("World");
		
      // 改变star1的值
      str1 = "Welcome";
      clos.call("World");
   } 
}

输出

Hello World 
Welcome World

当我们改变str1变量值的时候,其内部的获取到的值,也会跟着改变。

闭包参数

闭包可以用作方法的参数

class Example { 
    def static Display(clo) {
        // 执行闭包并传入参数   
        clo.call("Inner");
    } 

    static void main(String[] args) {
        def str1 = "Hello";
        def clos = { param -> println "${str1} ${param}" }
        clos.call("World");

        // 将闭包传入到方法
        Example.Display(clos);
    } 
}

输出

Hello World
Hello Inner

集合和字符串中的闭包

集合中,我们可以通过.each函数来传入一个闭包,并将闭包应用于集合中每一个元素

class Example {
   static void main(String[] args) {
      def lst = [11, 12, 13, 14];
      lst.each {println it}	// 传入闭包,it为单个隐式参数
   } 
}

输出

11 
12 
13 
14

键值对映射示例

class Example {
   static void main(String[] args) {
      def mp = ["TopicName" : "Maps", "TopicDescription" : "Methods in Maps"]             
      mp.each {println it}
      mp.each {println "${it.key} maps to: ${it.value}"}
   } 
}

输出

TopicName = Maps 
TopicDescription = Methods in Maps 
TopicName maps to: Maps 
TopicDescription maps to: Methods in Maps

异常

在Groovy 中对异常处理的写法更为宽松:如果没有在该代码块内通过 try-catch 处理异常,那么该异常就会自动地向上级抛出,且无需在函数声明中使用 throws 主动定义它们。

其它语法

非空则调用语法

在java中判断为空

String maybeNull = "I'm Java";
if(maybeNull != null){
    System.out.println(nullString.length());
}

而在 Groovy 中可以使用?.操作符来解决

String maybeNull = 'I\'m groovy'
print(maybeNull?.length())

精简的Bean

在编写bean时,可以使用def来表明其属性,不推荐

class Student_{
	final name
	def age
	Student_(name,age){
		this.name = name 
		this.age = age
	}
}

s = new Student_('Wang Fang',23)	//在使用时,会自动推导其属性的类型

省略构造器

class Student_{
    String name
    Integer age
}

// 没有实现 Student_(name,age) 构造器,但是可以直接使用
stu1 = new Student_(name: "Wang Fang",age: 12)

// 同样,我们也没有手动实现 Student_(name) 构造器。
stu2 = new Student_(name:"Wang Fang")

在未指定构造器的情况下我们可以使用键值对的形式去构建对象。

如果没有提供构造器,我们不能使用下面的方式进行创建对象。

stu1 = new Student_("Wang Fang",12)
stu2 = new Student_("Wang Fang")

除非手动补上其对应的构造器

多重赋值

def swap(x, y) { 
    return [y, x] 
}

Integer a, b
a = 10
b = 50

// 通过多重赋值实现了两数交换
(a, b) = swap(a, b)
print("a=$a,b=$b")

如果方法 ( 函数 ) 返回的是一个数组,那么 Groovy 支持使用多个变量接收数组内的元素内容。

如果接收的变量和返回值个数不匹配时,Groovy会进行如下操作

  • 如果接收的变量更多,那么会将没有赋值的变量赋为 null 。
  • 如果返回值更多,那么多余的返回值会被丢弃。

多方法接口实现

在java中实现一个接口方法可以通过匿名或者Lambda的方式来实现

Calculator<Integer> calculator = new Calculator<Integer>() {	// 匿名
    @Override
    public Integer add(Integer a, Integer b) {
        return a + b;
    }
};

Calculator<Integer> calculator = (a, b) -> a + b;	// Lambda

在Groovy中使用如下方法来实现

def a = {a,b ->return a+b} as Calculator<Integer>

如果接口是多方法,则可以通过封装一层Map来实现

interface Calculator<T> {
    T add(T a, T b)
    T sub(T a, T b)
}

def cal = [	//不同方法提供不同实现,通过as关键字来指定接口
        add: { a, b -> a + b },	
        sub: { a, b -> a - b }
] as Calculator<Integer>

def c = cal.sub(1,2)	//调用方法
print(c)

其它注解

@Canonical 替代 toString
@Canonical
// 如果不想打印 id 和 score,可以:
// @Canonical(excludes="id,score")
class Student {
    Integer id
    String name
    Integer age
    String major
    Integer score
}

// 如果没有此注解,打印的则是 Student@Hashcode
// 如果有注解,打印的则是 Student(1,"Wang Fang",20,"CS","score")
print new Student(id: 1,name:"Wang Fang",age: 20,major: "CS",score: 90.0d)
@Delegate 实现委托

使用 @Delegate 注解,在 Groovy 中实现方法委托非常容易。委托是继承以外的另一种代码复用的思路。在下面的代码块中,Manager 通过注解将 work() 方法委托给了内部的 worker 属性:

class Worker{
    void work(){
        print("worker is working exactly.")
    }
}

// Manager 获得了 Worker 的公开方法,尽管 worker 属性本身是 private.
class Manager{
    @Delegate private Worker worker = new Worker()	// 委托类
}

// 检查 Manager 实例有没有 work 方法,没有就去委托 worker 执行此方法。
new Manager().work()	// 调用委托类的方法
@Immutable 不可变对象

在java中创建不可变对象得使用final关键字,Groovy可以使用@Immutable注解来实现final修饰

@Immutable		// 修饰student类为不可变
class Student_{
    String id
    String name
}

def s = new Student_(id:"0001",name:"Wang Fang")

print s
@Newify 注解

允许我们创建对象时,忽略new关键字

class Student{
    String id
    String name
}

class Teacher{
    String id
    String name
}

@Newify(Student)
def getStudent(){
    // 在函数内部创建 Student 时,可以省略掉 new 关键字。
    Student(id:"0001",name: "Wang Fang")
}

// 多个类型使用数组的形式排列。
@Newify([Student,Teacher])
static def getStudentAndTeacher(){
    [Student(id:"0001",name:"Wang Fang"),Teacher(id: "0002",name:"Cheng Yu")]
}
@Singleton 单例模式
// 懒加载的单例模式,lazy 项是可选的。
@Singleton(lazy = true)
class TheUnique{
    {
        println "created only once"
    }
}

// 通过 .instance 调用这个单例对象。
TheUnique.instance

注意 Groovy 的 == 符号

在 Java 中,== 可以比较两个基本数据类型的值,或者比较两个引用类型的 HashCode。

而在 Groovy 当中,这两者的混乱程度有所加剧:Groovy 的 == 相当于是 Java 的 .equals() 方法或者是 compareTo() 方法 (见运算符重载的那个表格),而 Java 原始的 == 语义在 Groovy 中变成了 is() 方法。

str1 = "111"
str2 = "222"

// 相当于是 Java 语义中的 str1 == str2
str1.is(str2)

// 相当于是 Java 语义中的 str1.equals(str2)
str1 == str2

如果比较的类实现了 Compareble 接口,那么 == 的语义优先会选择 compareTo() 方法而非 equals() 方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值