Groovy 类
最后修改日期:2025 年 3 月 22 日
在本教程中,我们将探讨如何在 Groovy 中使用类。Groovy 是一种基于 Java 的动态、面向对象语言。Groovy 中的类是创建对象的模板(实例),Groovy 通过注解、自动属性和与 Java 相比更简洁的语法提供了灵活性。
Groovy 普通类
在 Groovy 中,class 关键字用于定义类,类是对象的模板。与 Java 不同,没有可见性修饰符的字段会成为具有自动 getter、setter 的属性,如果未提供无参构造函数,则会自动生成一个。没有修饰符的方法默认是 public 的。
import groovy.transform.Canonical
@Canonical
class User {
String name
String occupation
}
def u = new User('John Doe', 'gardener')
println u
println u.getName()
println u.getOccupation()
def u2 = new User('occupation': 'driver', 'name': 'Roger Roe')
println u2.name
println u2.occupation
在此,User 类使用了 @Canonical,这是一个 Groovy 注解,它会添加一个构造函数、toString、equals 和 hashCode。字段 name 和 occupation 是属性,会自动生成 getter/setter。我们通过 new User 或 map 风格的构造函数来创建实例,通过点 notation 或 getter 来访问字段。
$ groovy RegularClass.groovy User(John Doe, gardener) John Doe gardener User(Roger Roe, driver) Roger Roe driver
@Canonical
class User {
String name
String occupation
}
@Canonical 通过添加样板方法简化了类定义。没有修饰符的字段会成为具有自动访问器的 public 属性。
def u = new User('John Doe', 'gardener')
使用 @Canonical 添加的构造函数创建 User 实例,通过 new 调用。
def u2 = new User('occupation': 'driver', 'name': 'Roger Roe')
使用 Groovy 的 map 风格构造函数,利用 @Canonical 对命名参数的支持,增强了可读性和灵活性。
对象实例创建
Groovy 提供了多种实例化对象的方式,包括直接构造、类型转换和注解,与 Java 相比,对象创建更简洁、更具表现力。
class User {
String name
String occupation
User(String name, String occupation) {
this.name = name
this.occupation = occupation
}
String toString() {
"${this.name} is a ${this.occupation}"
}
}
def u = new User('John Doe', 'gardener')
println u
def u2 = ['Roger Roe', 'driver'] as User
println u2.name
println u2.occupation
User u3 = ['Paul Smith', 'teacher']
println u3
这展示了三种实例化方法:用于直接构造的 new User,使用 as User 进行类型转换,以及 Groovy 的隐式类型转换。toString 方法提供了可读的输出,属性自动处理访问。
$ groovy ObjectCreation.groovy John Doe is a gardener Roger Roe driver Paul Smith is a teacher
def u2 = ['Roger Roe', 'driver'] as User
将列表转换为 User 实例,匹配构造函数参数,展示了 Groovy 的动态类型和类型转换。
使用 tap 进行对象创建
Groovy 的 tap 方法允许进行流畅的对象初始化,它会执行一个闭包来设置新创建对象的属性。
class User {
String name
String occupation
String toString() {
"${this.name} is a ${this.occupation}"
}
}
def u = new User().tap {
name = 'John Doe'
occupation = 'gardener'
}
println u
tap 通过在闭包中设置属性来初始化 u,提供了一种干净、可链式调用的方式来构建对象,利用了 Groovy 的动态特性。
$ groovy TapCreation.groovy John Doe is a gardener
@TupleConstructor 注解
@TupleConstructor 注解会根据字段生成经典的构造函数,简化类定义,同时保持类似 Java 的结构。
import groovy.transform.TupleConstructor
@TupleConstructor
class User {
String name
String occupation
List<String> favcols
String toString() {
"${this.name} is a ${this.occupation}, favourite colours ${favcols}"
}
}
def u = new User('John Doe', 'gardener', ['red', 'green', 'blue'])
println u
@TupleConstructor 创建了一个按顺序接收所有字段的构造函数,这里是 name、occupation 和 favcols。属性会自动生成,toString 自定义输出,增强了 Groovy 相较于 Java 的简洁性。
$ groovy TupleConstructor.groovy John Doe is a gardener, favourite colours [red, green, blue]
@MapConstructor 注解
@MapConstructor 注解会生成一个基于 map 的构造函数,允许使用命名参数进行初始化,这是 Groovy 灵活性的一个标志。
import groovy.transform.MapConstructor
@MapConstructor
class User {
String name
String occupation
String toString() {
"${this.name} is a ${this.occupation}"
}
}
def u = new User(name: 'John Doe', occupation: 'gardener')
println u
@MapConstructor 允许使用 new User(name: ..., occupation:...),使用 map 进行初始化。属性会自动生成,使对象创建直观且易于阅读,与 Java 的僵化形成对比。
$ groovy MapConstructor.groovy John Doe is a gardener
使用 Immutable Classes 的 findAll
Groovy 的 @Immutable 注解创建了不可变类,非常适合数据对象,并与 findAll 结合用于过滤集合。
import groovy.transform.Immutable
@Immutable
class Task {
String title
boolean done
}
def tasks = [
new Task("Task 1", true), new Task("Task 2", true),
new Task("Task 3", false), new Task("Task 4", true),
new Task("Task 5", false)
]
def res = tasks.findAll { it.done == true }
println res
@Immutable 使 Task 不可变,生成一个构造函数并防止字段更改。findAll 过滤 tasks 以查找已完成的任务,返回 [Task(Task 1, true), ...],展示了 Groovy 的集合方法和不可变性以确保安全性。
$ groovy ImmutableFindAll.groovy [Task(Task 1, true), Task(Task 2, true), Task(Task 4, true)]
Groovy 抽象类
与 Java 一样,Groovy 使用 abstract 关键字支持抽象类,但它添加了动态功能。抽象类定义了未完成的行为,由子类实现,并且不能直接实例化。
abstract class Drawing {
protected int x = 0
protected int y = 0
abstract double area()
String getCoordinates() {
"x: ${x}, y: ${y}"
}
}
class Circle extends Drawing {
private int r
Circle(int x, int y, int r) {
this.x = x
this.y = y
this.r = r
}
@Override
double area() {
this.r * this.r * Math.PI
}
String toString() {
"Circle at x: ${x}, y: ${y}, radius: ${r}"
}
}
def c = new Circle(12, 45, 22)
println c
println "Area of circle: ${c.area()}"
println c.getCoordinates()
Drawing 抽象类将 area() 声明为抽象,要求在 Circle 中实现。Groovy 的动态类型和字符串插值简化了语法,同时保持了 Java 在继承和多态方面的兼容性。
$ groovy AbstractClass.groovy Circle at x: 12, y: 45, radius: 22 Area of circle: 1520.53084433746 x: 12, y: 45
Groovy 嵌套类
Groovy 支持像 Java 一样的嵌套类,包括静态嵌套类、内部类、局部类和匿名类,但具有 Groovy 的动态特性以实现简洁性。嵌套类可以提高代码组织性和可读性。
// Static Nested Class
class Outer {
static int x = 5
static class Nested {
String toString() { "Static nested; x: ${x}" }
}
}
def sn = new Outer.Nested()
println sn
// Inner Class
class InnerTest {
int x = 5
class Inner {
String toString() { "Inner class; x: ${x}" }
}
}
def it = new InnerTest()
def inner = it.new Inner()
println inner
Groovy 的静态嵌套类 Nested 访问 Outer 的静态 x,而内部类 Inner 访问 InnerTest 的实例 x。Groovy 通过省略显式访问修饰符来简化语法,但保留了 Java 的结构以实现兼容性。
$ groovy NestedClasses.groovy Static nested; x: 5 Inner class; x: 5
@InheritConstructors 注解
Groovy 的 @InheritConstructors 注解会自动从超类继承构造函数,从而减少了子类定义的样板代码。
import groovy.transform.InheritConstructors
class Parent {
String name
Parent(String name) { this.name = name }
}
@InheritConstructors
class Child extends Parent { }
def c = new Child('John Doe')
println c.name
@InheritConstructors 允许 Child 继承 Parent 的构造函数,创建了一个名为 "John Doe" 的 Child。此注解简化了继承,增强了 Groovy 相较于 Java 手动复制构造函数的生产力。
$ groovy InheritConstructors.groovy John Doe
来源
本教程探讨了 Groovy 中类的工作方式,重点介绍了其动态特性、注解和对象创建方法,在 Java 的 OOP 基础上增加了灵活性。
作者
列出 所有 Groovy 教程。