Лучший способ исследовать проблему такого рода - это посмотреть на сгенерированный байт-код самостоятельно.Если вы создаете два примера классов:
WithType.groovy:
class WithType {
String name
String returnName() { getName() }
}
WithoutType.groovy:
class WithoutType {
def name
def returnName() { getName() }
}
Скомпилируйте их с помощью groovyc
:
% groovyc WithType.groovy
% groovyc WithoutType.groovy
А затем используйте javap
, чтобы выплюнуть читабельный для человека байт-код:
% javap -c WithType > WithType.txt
% javap -c WithoutType > WithoutType.txt
Затем вы можете просмотреть 2 файла и найти метод returnName()
, чтобы увидеть, как они обрабатываются.иначе как они вызывают сгенерированный getName()
метод для поля имени.Если вы найдете метод returnName()
, вы увидите, что версия WithType выглядит следующим образом:
public java.lang.String returnName();
Code:
0: invokestatic #24; //Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
3: astore_1
4: aload_1
5: ldc #47; //int 0
7: aaload
8: aload_0
9: invokeinterface #53, 2; //InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callCurrent:(Lgroovy/lang/GroovyObject;)Ljava/lang/Object;
14: invokestatic #56; //Method $get$$class$java$lang$String:()Ljava/lang/Class;
17: invokestatic #38; //Method org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType:(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
20: checkcast #58; //class java/lang/String
23: areturn
24: nop
, а нетипизированная выглядит так:
public java.lang.Object returnName();
Code:
0: invokestatic #24; //Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
3: astore_1
4: aload_1
5: ldc #47; //int 0
7: aaload
8: aload_0
9: invokeinterface #53, 2; //InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callCurrent:(Lgroovy/lang/GroovyObject;)Ljava/lang/Object;
14: areturn
15: nop
Нетипизированнаяимеет меньше инструкций, потому что ему не нужно выполнять какую-либо проверку типа или преобразование строки в том, что он возвращает.Фактический вызов метода для getName()
одинаков как в типизированной, так и в нетипизированной версиях:
9: invokeinterface #53, 2; //InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callCurrent:(Lgroovy/lang/GroovyObject;)Ljava/lang/Object;
Вы можете видеть, что он вызывает интерфейсный метод в методе Groovy CallSite и передает GroovyObject. CallSite - это интерфейс, который реализован с помощью отличного кода метаобъекта.Так что это вызов Groovy MOP, который динамически вызывает метод getName()
.
(это все с groovy 1.7.5)