Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java vs. Groovy inner / outer class discrepancy

Java:

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");
   }
}

Output when run:

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()
    }
  }
}

Output when run:

$ 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)

Why this discrepancy? Using Outer.outer() works, however any way to avoid typing the class name?

like image 883
levant pied Avatar asked Oct 30 '14 17:10

levant pied


People also ask

Can inner class use outer class variables Java?

Method Local inner classes can't use a local variable of the outer method until that local variable is not declared as final.

Can inner class access outer class methods?

An instance of InnerClass can exist only within an instance of OuterClass and has direct access to the methods and fields of its enclosing instance. To instantiate an inner class, you must first instantiate the outer class.

What is the main difference between an inner class and a static nested class in Java?

1) First and most important difference between Inner class and nested static class is that Inner class require instance of outer class for initialization and they are always associated with instance of enclosing class. On the other hand nested static class is not associated with any instance of enclosing class.

Can Java inner class be static?

A static class is a class that is created inside a class, is called a static nested class in Java. It cannot access non-static data members and methods. It can be accessed by outer class name.


2 Answers

You can add an import static Outer.outer to top of the script to avoid typing the class name (kinda)...you at least avoid typing it inside the method.

To complement the already-provided explanation, if you inspect the AST Browser inside Groovy Console at the Output stage, you can see that both classes are top-level, so "Inner" can't resolve to Outer's methods without the import.

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 { 

}
like image 63
bdkosher Avatar answered Sep 19 '22 07:09

bdkosher


Groovy's default behavior is dynamic: it resolves the reference at runtime, not compile time. In Java, the compiler recognizes the call to outer() is static and actually resolves it to the parent class. In the bytecode, you will find a fully-qualified reference to the static method being invoked. (The parent class in this case.) Groovy, by contrast, resolves the call at runtime (unless you use the @CompileStatic annotation) and so the bytecode generated by the Groovy compiler will not have a fully-qualified reference. Therefore, at runtime, Groovy will not know that the method is found only in the parent class, it will simply try to resolve it in the inner class, which will fail.

Minor discrepancy: your Groovy methods are returning Object, while the Java methods are void. This isn't necessarily a big deal, but it will create compatibility problems if your Java code is calling Groovy objects and you make changes.

like image 38
ngreen Avatar answered Sep 20 '22 07:09

ngreen