2014-10-30 9 views
6

Java:Java vs Groovy wewnętrznej/zewnętrznej klasy rozbieżności

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

Wyjście podczas uruchamiania:

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

Wyjście podczas uruchamiania:

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

Dlaczego ta rozbieżność? Czy używasz Outer.outer(), aby uniknąć wpisywania nazwy klasy?

Odpowiedz

4

Możesz dodać import static Outer.outer na początek skryptu, aby uniknąć wpisywania nazwy klasy (kinda) ... przynajmniej unikaj wpisywania jej wewnątrz metody.

Aby uzupełnić już dostarczone wyjaśnienie, jeśli przejrzysz przeglądarkę AST wewnątrz Konsoli Groovy na etapie Wyjścia, możesz zobaczyć, że obie klasy są na najwyższym poziomie, więc "Wewnętrzny" nie może zostać rozwiązany na zewnątrz metod bez 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 { 

} 
+0

Dzięki! :(<--- moja smutna twarz –

3

Domyślne zachowanie Groovy jest dynamiczne: rozwiązuje odniesienie w czasie wykonywania, a nie podczas kompilacji. W Javie kompilator rozpoznaje, że wywołanie outer() jest statyczne i faktycznie rozwiązuje je dla klasy nadrzędnej. W kodzie bajtowym znajduje się pełne odwołanie do wywoływanej metody statycznej. (W tym przypadku klasa nadrzędna.) W przeciwieństwie do tego Groovy rozstrzyga połączenie w czasie wykonywania (chyba że używa się adnotacji @CompileStatic), a więc kod bajtowy wygenerowany przez kompilator Groovy nie będzie miał pełnego odwołania. Dlatego w czasie wykonywania Groovy nie będzie wiedział, że metoda zostanie znaleziona tylko w klasie nadrzędnej, po prostu spróbuje ją rozwiązać w klasie wewnętrznej, co zakończy się niepowodzeniem.

Niewielka rozbieżność: Twoje metody Groovy wracają Object, a metody Java to void. Niekoniecznie jest to wielka sprawa, ale spowoduje to problemy z kompatybilnością, jeśli twój kod Java wywoła obiekty Groovy i wprowadzisz zmiany.