Java与Groovy内/外类差异

时间:2014-10-30 17:28:21

标签: java groovy groovyshell

爪哇:

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()无论如何都可以避免输入类名吗?

2 个答案:

答案 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对象并进行更改,则会产生兼容性问题。