本篇内容为Groovy学习第32篇,学习Groovy语法中的提升与强制转换相关知识点。(Promotion和coercion)
在潮安等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供网站制作、成都做网站 网站设计制作按需制作,公司网站建设,企业网站建设,高端网站设计,成都全网营销,成都外贸网站制作,潮安网站建设费用合理。
学习在Groovy中的各种数据类型的各种强制转换和类型变换。
如果不了解Groovy中的数据时如何进行转换的,那么可以学习一下本篇内容,应该能够给你一些参考。
整数提升:数字提升的规则在数学运算一节中有详细说明。[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 |
不同数值之间的提升,是按照该表格的关系进行的。
在前面介绍闭包相关知识的时候,有介绍过闭包中的各种转换,相关知识点可以通过:https://zinyan.com/?p=461,https://zinyan.com/?p=462,https://zinyan.com/?p=463了解。
这里只是进行简单的复习和介绍。
2.2.1 SAM单例对象,进行闭包转换
SAM类型是定义单个抽象方法的类型。例如我们创建接口:它的入参是个T泛型。
interface Predicate{
boolean accept(T obj)
}
具有单个抽象方法的抽象类:
abstract class Zinyan {
abstract String getName()
void hello() {
println "Hello, $name"
}
}
可以使用as运算符将任何闭包转换为SAM类型:
Predicate filter = { it.contains 'G' } as Predicate
assert filter.accept('Groovy') == true
Greeter greeter = { 'Groovy' } as Greeter
greeter.hello() //输出:Hello, Groovy
从Groovy 2.2.0 开始,as Type表达式是可选的。我们可以省略它,只需编写:
Predicate filter = { it.contains 'G' }
assert filter.accept('Groovy') == true
Greeter greeter = { 'Groovy' }
greeter.hello() //输出:Hello, Groovy
PS: 上面的 { it.contains 'G' }就是一个闭包对象哦
这意味着我们也可以使用方法指针,如下例所示:
boolean doFilter(String s) { s.contains('G') }
Predicate filter = this.&doFilter
assert filter.accept('Groovy') == true
Greeter greeter = GroovySystem.&getVersion
greeter.hello() //输出:Hello, Groovy
2.2.2 调用接受带有闭包的SAM类型的方法
关闭SAM类型强制的第二个也是可能更重要的用例是调用接受SAM类型的方法。设想以下方法:
publicList filter(List source, Predicate predicate) {
source.findAll { predicate.accept(it) }
}
然后,可以使用闭包调用它,而无需创建接口的显式实现:
assert filter(['Java','Groovy'], { it.contains 'G'} as Predicate) == ['Groovy']
从Groovy 2.2.0开始,还可以省略显式强制,并像使用闭包一样调用该方法:
assert filter(['Java','Groovy']) { it.contains 'G'} == ['Groovy']
这样做的优点是允许我们在方法调用中使用闭包语法,也就是说,将闭包放在括号之外,从而提高了代码的可读性。
2.2.3 对任意类型的强制闭包
上面介绍了SAM单例对象的强制转换,这里介绍其他的类型。
除了SAM类型之外,闭包还可以强制到任何类型,尤其是特定的接口。让我们定义以下接口:
interface FooBar {
int foo()
void bar()
}
定义了一个接口对象,它有两个方法分别是foo和bar。我们可以使用as关键字将闭包强制到接口中:
def impl = { println 'ok'; 123 } as FooBar
这将生成一个类,所有方法都使用闭包实现:
assert impl.foo() == 123
impl.bar() //输出: ok
但也可以强制对任何类进行闭包。例如,我们可以用class替换我们定义的接口,而不改变assert断言的结果:
class FooBar {
int foo() { 1 }
void bar() { println 'bar' }
}
def impl = { println 'ok'; 123 } as FooBar
assert impl.foo() == 123
impl.bar()
PS: 断言结果不满足是会出新错误并停止程序继续执行的
通常使用一个闭包来实现一个接口或一个具有多个方法的类是不可行的。作为替代方案,Groovy允许将Map强制到接口或类中。在这种情况下,Map的键被解释为方法名,而值是方法实现。以下示例说明了将Map强制到迭代器中:
def map
map = [
i: 10,
hasNext: { map.i > 0 },
next: { map.i-- },
]
def iter = map as Iterator
当然,这是一个相当做作的例子,但说明了这个概念。我们只需要实现那些实际调用的方法,但如果调用的方法在映射中不存在,则会引发MissingMethodException或
UnsupportedOperationException,具体取决于传递给调用的参数,如下例所示:
interface X {
void f()
void g(int n)
void h(String s, int n)
}
x = [ f: {println "f called"} ] as X
x.f() // 正常的方法调用
x.g() // MissingMethodException 异常触发
x.g(5) // UnsupportedOperationException 异常触发
异常的类型取决于调用本身:
MissingMethodException:如果调用的参数与接口/类中的参数不匹配,就会触发该异常警告。
UnsupportedOperationException:如果调用的参数与接口/类的重载方法之一匹配,就会触发该异常警告。
Groovy允许透明String(或GString)强制枚举值。假设定义了以下枚举:
enum State {
up,
down
}
则可以将字符串分配给枚举,而不必使用显式作为强制:
State st = 'up'
assert st == State.up
也可以使用GString作为值:
def val = "up"
State st = "${val}"
assert st == State.up
但是,这会引发运行时错误(IllegalArgumentException):
State st = 'not an enum value'
注意,也可以在switch语句中使用隐式强制:
State switchState(State st) {
switch (st) {
case 'up':
return State.down // 显式赋值
case 'down':
return 'up' // 返回类型的隐式强制
}
}
特别是,请查看case如何使用字符串常量。但如果调用一个使用带有String参数的枚举的方法,则仍必须使用as作为强制:
assert switchState('up' as State) == State.down
assert switchState(State.down) == State.up
类可以通过实现asType方法来定义自定义强制策略。自定义强制是使用as运算符调用的,并且从不隐式。例如,假设定义了两个类,Polar和Cartesian,如以下示例所示:
class Polar {
double r
double phi
}
class Cartesian {
double x
double y
}
你想从极坐标转换成笛卡尔坐标。一种方法是在Polar类中定义asType方法:
def asType(Class target) {
if (Cartesian==target) {
return new Cartesian(x: r*cos(phi), y: r*sin(phi))
}
}
这允许使用as强制运算符:
def sigma = 1E-16
def polar = new Polar(r:1.0,phi:PI/2)
def cartesian = polar as Cartesian
assert abs(cartesian.x-sigma) < sigma
把所有这些放在一起,Polar类看起来像这样:
class Polar {
double r
double phi
def asType(Class target) {
if (Cartesian==target) {
return new Cartesian(x: r*cos(phi), y: r*sin(phi))
}
}
}
但也可以在Polar类之外定义asType,如果想为“封闭”类或不拥有源代码的类定义自定义强制策略,例如使用元类:
Polar.metaClass.asType = { Class target ->
if (Cartesian==target) {
return new Cartesian(x: r*cos(phi), y: r*sin(phi))
}
}
PS: 自定义类型转换主要的就是关键方法asType了。实现asType方法,然后自己就可以定义各种类型的转换了。
只有对类有静态引用时,才能使用as关键字,如以下代码所示:
interface Greeter {
void greet()
}
def greeter = { println 'Hello, Groovy!' } as Greeter // Greeter is known statically
greeter.greet()
但是,如果通过反射获得类,例如通过调用class.forName,该怎么办?
Class clazz = Class.forName('Greeter')
尝试使用as关键字对类的引用将失败:
greeter = { println 'Hello, Groovy!' } as clazz
// throws:
// unable to resolve class clazz
// @ line 9, column 40.
// greeter = { println 'Hello, Groovy!' } as clazz
会出现异常错误,因为as关键字只对类文本有效。我们需要调用asType方法:
greeter = { println 'Hello, Groovy!' }.asType(clazz)
greeter.greet()
到这里,Groovy中有关于强制转换和类型提升的相关知识就分享完毕了。以上内容可以通过Groovy官网文档:
[Groovy Language Documentation (groovy-lang.org)](http://docs.groovy-lang.org/docs/groovy-4.0.6/html/documentation/#_promotion_and_coercion)深入学习。
网页标题:Groovy语法Promotion提升和Coercion强制转换学习
转载来于:http://www.36103.cn/qtweb/news30/38280.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联