Groovy 快速入门_groovy入门-程序员宅基地

技术标签: 经验分享  java  Groovy  


在这里插入图片描述

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 中的用法一样

as assert break case
catch class const continue
def default do else
enum extends false Finally
for goto if implements
import in instanceof interface
new pull package return
super switch this throw
throws trait true try
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() 方法。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hkdwsw/article/details/124886540

智能推荐

前端开发之vue-grid-layout的使用和实例-程序员宅基地

文章浏览阅读1.1w次,点赞7次,收藏34次。vue-grid-layout的使用、实例、遇到的问题和解决方案_vue-grid-layout

Power Apps-上传附件控件_powerapps点击按钮上传附件-程序员宅基地

文章浏览阅读218次。然后连接一个数据源,就会在下面自动产生一个添加附件的组件。把这个控件复制粘贴到页面里,就可以单独使用来上传了。插入一个“编辑”窗体。_powerapps点击按钮上传附件

C++ 面向对象(Object-Oriented)的特征 & 构造函数& 析构函数_"object(cnofd[\"ofdrender\"])十条"-程序员宅基地

文章浏览阅读264次。(1) Abstraction (抽象)(2) Polymorphism (多态)(3) Inheritance (继承)(4) Encapsulation (封装)_"object(cnofd[\"ofdrender\"])十条"

修改node_modules源码,并保存,使用patch-package打补丁,git提交代码后,所有人可以用到修改后的_修改 node_modules-程序员宅基地

文章浏览阅读133次。删除node_modules,重新npm install看是否成功。在 package.json 文件中的 scripts 中加入。修改你的第三方库的bug等。然后目录会多出一个目录文件。_修改 node_modules

【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure-程序员宅基地

文章浏览阅读883次。【代码】【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure

整理5个优秀的微信小程序开源项目_微信小程序开源模板-程序员宅基地

文章浏览阅读1w次,点赞13次,收藏97次。整理5个优秀的微信小程序开源项目。收集了微信小程序开发过程中会使用到的资料、问题以及第三方组件库。_微信小程序开源模板

随便推点

Centos7最简搭建NFS服务器_centos7 搭建nfs server-程序员宅基地

文章浏览阅读128次。Centos7最简搭建NFS服务器_centos7 搭建nfs server

Springboot整合Mybatis-Plus使用总结(mybatis 坑补充)_mybaitis-plus ruledataobjectattributemapper' and '-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏3次。前言mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。..._mybaitis-plus ruledataobjectattributemapper' and 'com.picc.rule.management.d

EECE 1080C / Programming for ECESummer 2022 Laboratory 4: Global Functions Practice_eece1080c-程序员宅基地

文章浏览阅读325次。EECE 1080C / Programming for ECESummer 2022Laboratory 4: Global Functions PracticePlagiarism will not be tolerated:Topics covered:function creation and call statements (emphasis on global functions)Objective:To practice program development b_eece1080c

洛谷p4777 【模板】扩展中国剩余定理-程序员宅基地

文章浏览阅读53次。被同机房早就1年前就学过的东西我现在才学,wtcl。设要求的数为\(x\)。设当前处理到第\(k\)个同余式,设\(M = LCM ^ {k - 1} _ {i - 1}\) ,前\(k - 1\)个的通解就是\(x + i * M\)。那么其实第\(k\)个来说,其实就是求一个\(y\)使得\(x + y * M ≡ a_k(mod b_k)\)转化一下就是\(y * M ...

android 退出应用没有走ondestory方法,[Android基础论]为何Activity退出之后,系统没有调用onDestroy方法?...-程序员宅基地

文章浏览阅读1.3k次。首先,问题是如何出现的?晚上复查代码,发现一个activity没有调用自己的ondestroy方法我表示非常的费解,于是我检查了下代码。发现再finish代码之后接了如下代码finish();System.exit(0);//这就是罪魁祸首为什么这样写会出现问题System.exit(0);////看一下函数的原型public static void exit (int code)//Added ..._android 手动杀死app,activity不执行ondestroy

SylixOS快问快答_select函数 导致堆栈溢出 sylixos-程序员宅基地

文章浏览阅读894次。Q: SylixOS 版权是什么形式, 是否分为<开发版税>和<运行时版税>.A: SylixOS 是开源并免费的操作系统, 支持 BSD/GPL 协议(GPL 版本暂未确定). 没有任何的运行时版税. 您可以用她来做任何 您喜欢做的项目. 也可以修改 SylixOS 的源代码, 不需要支付任何费用. 当然笔者希望您可以将使用 SylixOS 开发的项目 (不需要开源)或对 SylixOS 源码的修改及时告知笔者.需要指出: SylixOS 本身仅是笔者用来提升自己水平而开发的_select函数 导致堆栈溢出 sylixos

推荐文章

热门文章

相关标签