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 教程。