爪哇:
public final class Outer {
public static void main(String[] args) {
Inner.inner();
}
private static final class Inner {
private static void inner() {
System.out.println("inner");
outer();
}
}
private static void outer() {
System.out.println("outer");
}
}
运行时输出:
inner
outer
Groovy的:
public final class Outer {
static main(String[] args) {
Inner.inner()
}
static outer() {
println('outer')
}
static final class Inner {
static inner() {
println('inner')
outer()
}
}
}
运行时输出:
$ groovy Outer
inner
Caught: groovy.lang.MissingMethodException: No signature of method: static Outer$Inner.outer() is applicable for argument types: () values: []
Possible solutions: inner(), use([Ljava.lang.Object;), use(java.lang.Class, groovy.lang.Closure), use(java.util.List, groovy.lang.Closure), putAt(java.lang.String, java.lang.Object), grep()
groovy.lang.MissingMethodException: No signature of method: static Outer$Inner.outer() is applicable for argument types: () values: []
Possible solutions: inner(), use([Ljava.lang.Object;), use(java.lang.Class, groovy.lang.Closure), use(java.util.List, groovy.lang.Closure), putAt(java.lang.String, java.lang.Object), grep()
at Outer$Inner.inner(Outer.groovy:13)
at Outer$Inner$inner.call(Unknown Source)
at Outer.main(Outer.groovy:3)
为什么会出现这种差异?使用Outer.outer()
无论如何都可以避免输入类名吗?
答案 0 :(得分:4)
您可以在脚本顶部添加import static Outer.outer
以避免输入类名(有点)...至少避免在方法内输入。
为了补充已经提供的解释,如果你在输出阶段检查Groovy控制台内的AST浏览器,你会发现这两个类都是顶级的,所以"内部"在没有导入的情况下无法解析为Outer的方法。
final public class Outer implements groovy.lang.GroovyObject extends java.lang. Object {
}
final public static class Outer$Inner implements groovy.lang.GroovyObject extends java.lang.Object {
}
答案 1 :(得分:3)
Groovy的默认行为是动态的:它在运行时解析引用,而不是编译时。在Java中,编译器识别对outer()
的调用是静态的,并实际将其解析为父类。在字节码中,您将找到对要调用的静态方法的完全限定引用。 (在这种情况下是父类。)相反,Groovy在运行时解析调用(除非您使用@CompileStatic
注释),因此Groovy编译器生成的字节码将没有完全限定的引用。因此,在运行时,Groovy不会知道该方法只在父类中找到,它只会尝试在内部类中解析它,这将失败。
轻微差异:您的Groovy方法返回Object
,而Java方法是void
。这并不是什么大不了的事,但如果您的Java代码调用Groovy对象并进行更改,则会产生兼容性问题。