2021SC@SDUSC
Groovy与Java的主要区别
分析了这么久的Groovy,最后我们来总结一下Groovy与我之前学习的Java的主要区别。
默认 imports
所有这些包和类都是默认导入的,你不必使用显式import语句来使用它们:
java.io.*
java.lang.*
java.math.BigDecimal
java.math.BigInteger
java.net.*
java.util.*
groovy.lang.*
groovy.util.*
额外的关键字
Groovy中还要比Java多几个关键字。 不要将它们用于变量名称等。
as
def
in
trait
Multi-methods
在Groovy中,将在运行时选择将被调用的方法。 这称为运行时分派或Multi-methods
。 这意味着将基于运行时参数的类型来选择方法。 在Java中,则是根据声明的类型,在编译时选择方法。
下面的代码,以Java代码编写,可以在Java和Groovy中编译,但它的行为会有所不同:
int method(String arg) {
return 1;
}
int method(Object arg) {
return 2;
}
Object o = "Object";
int result = method(o);
在Java中, 得到:
assertEquals(2, result);
而在Groovy中:
assertEquals(1, result);
这是因为Java将使用静态信息类型,即o
被声明为Object
,而Groovy将在运行时选择该方法被实际调用时。 因为它是用String
调用的,所以调用String
版本。
==
的行为
在Java中==
表示对象的原始类型或标识的相等性。 在Groovy ==
翻译为a.compareTo(b)== 0
,如果他们是可比较的,否则a.equals(b)
。 如果要检查身份,有is
方法,例如a.is(b)
。
数组初始化
在Groovy中,{...}块是为闭包而保留的。 这意味着您不能使用以下语法创建数组literal:
int [] array = {1,2,3}
实际上你必须使用:
int [] array = [1,2,3]
GStrings
由于双引号字符串字面量被解释为GString
,如果具有包含美元字符的String
的类是使用Groovy和Java编译器编译的,Groovy可能会失败并产生编译错误或产生细微不同的代码。
通常,Groovy将在GString
和String
之间自动转换,如果API声明参数的类型,小心接受Object
参数的Java API,然后检查实际的类型。
原始和封装
因为Groovy使用Objects来做每一件事,它对原始的引用自动包装。 因此,它不遵循Java的行为扩展优先于装箱。 这里有一个使用int的例子。
int i
m(i)
//这是Java将调用的方法,因为扩展优先于拆箱。
void m(long l) {
println "in m(long)"
}
//这是Groovy实际调用的方法,因为所有的基本引用都使用它们的包装类。
void m(Integer i) {
println "in m(Integer)"
}
包范围可见性
在Groovy中,在字段上省略修饰符不会像Java中一样变成package-private
字段:
class Person {
字符串名称
}}
相反,它用于创建一个属性,也就是说一个私有字段,一个关联的getter
和一个关联的setter
。
可以通过使用@PackageScope注释来创建一个package-private
字段:
class Person {
@PackageScope字符串名称
}}
内部类
匿名内部类和嵌套类的实现遵循Java方式,但是你不应该拿出Java语言规范,并且对不同的东西不断地摇头。 它的实现看起来很像groovy.lang.Closure
,同时有一些好处和一些差异。 例如访问私有字段和方法可能成为一个问题,但另一方面,局部变量不必是final的。
- 静态内部类
这里有一个静态内部类的例子:class A { static class B {} } new A.B()
静态内部类的使用是最好的支持。 如果你需要一个内部类,你最好使用静态的。
- 匿名内部类
import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit CountDownLatch called = new CountDownLatch(1) Timer timer = new Timer() timer.schedule(new TimerTask() { void run() { called.countDown() } }, 0) assert called.await(10, TimeUnit.SECONDS)
- 创建非静态内部类的实例
在Java中,你可以这样做:public class Y { public class X {} public X foo() { return new X(); } public static X createX(Y y) { return y.new X(); } }
Groovy不支持
y.new X()
语法。 相反,你必须用new X(y)
,如下面的代码:public class Y { public class X {} public X foo() { return new X() } public static X createX(Y y) { return new X(y) } }
注意,Groovy支持使用一个参数调用方法,而不提供参数。 然后,参数的值为null。 基本上,相同的规则适用于调用构造函数。 有一个危险,例如你会写new X(),而不是new X(this)。 由于这也可能是正常的方式,目前还没有一个好的方法来防止这个问题。