1. 介绍
本篇内容为Groovy学习第32篇,学习Groovy语法中的提升与强制转换相关知识点。(Promotion和coercion)
学习在Groovy中的各种数据类型的各种强制转换和类型变换。
如果不了解Groovy中的数据时如何进行转换的,那么可以学习一下本篇内容,应该能够给你一些参考。
2. 提升和强制转换
2.1 数值转换
整数提升:数字提升的规则在数学运算一节中有详细说明。[4. Groovy语法-Number和Boolean数据类型学习 (zinyan.com)](https://zinyan.com/?p=389#2.5-数学运算)
主要就是下图所示的,数值类型的转换。
byte | char | short | int | long | BigInteger | float | double | BigDecimal | |
byte | int | int | int | int | long | BigInteger | double | double | BigDecimal |
char | int | int | int | long | BigInteger | double | double | BigDecimal | |
short | int | int | long | BigInteger | double | double | BigDecimal | ||
int | int | long | BigInteger | double | double | BigDecimal | |||
long | long | BigInteger | double | double | BigDecimal | ||||
BigInteger | BigInteger | double | double | BigDecimal | |||||
float | double | double | double | ||||||
double | double | double | |||||||
BigDecimal | BigDecimal |
不同数值之间的提升,是按照该表格的关系进行的。
2.2 闭包closure的类型转换
在前面介绍闭包相关知识的时候,有介绍过闭包中的各种转换,相关知识点可以通过:https://zinyan.com/?p=461,https://zinyan.com/?p=462,https://zinyan.com/?p=463了解。
这里只是进行简单的复习和介绍。
2.2.1 SAM单例对象,进行闭包转换
SAM类型是定义单个抽象方法的类型。例如我们创建接口:它的入参是个T泛型。
具有单个抽象方法的抽象类:
可以使用as运算符将任何闭包转换为SAM类型:
从Groovy 2.2.0 开始,as Type表达式是可选的。我们可以省略它,只需编写:
PS: 上面的 { it.contains 'G' }就是一个闭包对象哦
这意味着我们也可以使用方法指针,如下例所示:
2.2.2 调用接受带有闭包的SAM类型的方法
关闭SAM类型强制的第二个也是可能更重要的用例是调用接受SAM类型的方法。设想以下方法:
然后,可以使用闭包调用它,而无需创建接口的显式实现:
从Groovy 2.2.0开始,还可以省略显式强制,并像使用闭包一样调用该方法:
这样做的优点是允许我们在方法调用中使用闭包语法,也就是说,将闭包放在括号之外,从而提高了代码的可读性。
2.2.3 对任意类型的强制闭包
上面介绍了SAM单例对象的强制转换,这里介绍其他的类型。
除了SAM类型之外,闭包还可以强制到任何类型,尤其是特定的接口。让我们定义以下接口:
定义了一个接口对象,它有两个方法分别是foo和bar。我们可以使用as关键字将闭包强制到接口中:
这将生成一个类,所有方法都使用闭包实现:
但也可以强制对任何类进行闭包。例如,我们可以用class替换我们定义的接口,而不改变assert断言的结果:
PS: 断言结果不满足是会出新错误并停止程序继续执行的
2.3 Map强制转换成类型
通常使用一个闭包来实现一个接口或一个具有多个方法的类是不可行的。作为替代方案,Groovy允许将Map强制到接口或类中。在这种情况下,Map的键被解释为方法名,而值是方法实现。以下示例说明了将Map强制到迭代器中:
当然,这是一个相当做作的例子,但说明了这个概念。我们只需要实现那些实际调用的方法,但如果调用的方法在映射中不存在,则会引发MissingMethodException或
UnsupportedOperationException,具体取决于传递给调用的参数,如下例所示:
异常的类型取决于调用本身:
MissingMethodException:如果调用的参数与接口/类中的参数不匹配,就会触发该异常警告。
UnsupportedOperationException:如果调用的参数与接口/类的重载方法之一匹配,就会触发该异常警告。
2.4 String强制转换成enum
Groovy允许透明String(或GString)强制枚举值。假设定义了以下枚举:
则可以将字符串分配给枚举,而不必使用显式作为强制:
也可以使用GString作为值:
但是,这会引发运行时错误(IllegalArgumentException):
注意,也可以在switch语句中使用隐式强制:
特别是,请查看case如何使用字符串常量。但如果调用一个使用带有String参数的枚举的方法,则仍必须使用as作为强制:
2.5 自定义类型强制转换
类可以通过实现asType方法来定义自定义强制策略。自定义强制是使用as运算符调用的,并且从不隐式。例如,假设定义了两个类,Polar和Cartesian,如以下示例所示:
你想从极坐标转换成笛卡尔坐标。一种方法是在Polar类中定义asType方法:
这允许使用as强制运算符:
把所有这些放在一起,Polar类看起来像这样:
但也可以在Polar类之外定义asType,如果想为“封闭”类或不拥有源代码的类定义自定义强制策略,例如使用元类:
PS: 自定义类型转换主要的就是关键方法asType了。实现asType方法,然后自己就可以定义各种类型的转换了。
2.6 类文本vs变量和as运算符
只有对类有静态引用时,才能使用as关键字,如以下代码所示:
但是,如果通过反射获得类,例如通过调用class.forName,该怎么办?
尝试使用as关键字对类的引用将失败:
会出现异常错误,因为as关键字只对类文本有效。我们需要调用asType方法:
3. 小结
到这里,Groovy中有关于强制转换和类型提升的相关知识就分享完毕了。以上内容可以通过Groovy官网文档:
[Groovy Language Documentation (groovy-lang.org)](http://docs.groovy-lang.org/docs/groovy-4.0.6/html/documentation/#_promotion_and_coercion)深入学习。