Почему checkcast-инструкция отсутствует для (int)MethodHandle.invokeExact?

Я создал 2 простых класса для попробовать Java MethodHandle-API:

public class Foo {
    private static int staticField;

    public static Object getStaticField() {
        return staticField;
    }
}

другой класс для вызова метода Foo.getStaticField() двумя способами - прямым и использованием MethodHandle-API:

....
public static void methodHandleGetStaticField() throws Throwable {
    MethodHandle methodHandle = lookup.findStatic(Foo.class, "getStaticField", MethodType.methodType(int.class));
    int i = (int)methodHandle.invokeExact();
}

public static void directGetStaticField() {
    int i = (int)Foo.getStaticField();
}
....

Я декомпилировал класс и увидел, что directGetStaticField метод содержит приведенные инструкции, но метод methodHandleGetStaticField нет, хотя java.lang.invoke.MethodHandle.invokeExact() возвращается java.lang.Object,

public static void directGetStaticField();
descriptor: ()V
Code:
   0: invokestatic  #70    // Method ru/fj/methodhandle/Foo.getStaticField:()Ljava/lang/Object;
   3: checkcast     #33    // class java/lang/Integer
   6: invokevirtual #74    // Method java/lang/Integer.intValue:()I
   9: istore_0
  10: return

public static void methodHandleGetStaticField() throws java.lang.Throwable;
descriptor: ()V
Code:
   0: getstatic     #15    // Field lookup:Ljava/lang/invoke/MethodHandles$Lookup;
   3: ldc           #29    // class ru/fj/methodhandle/Foo
   5: ldc           #90    // String getStaticField
   7: getstatic     #32    // Field java/lang/Integer.TYPE:Ljava/lang/Class;
  10: invokestatic  #38    // Method java/lang/invoke/MethodType.methodType:(Ljava/lang/Class;)Ljava/lang/invoke/MethodType;
  13: invokevirtual #46    // Method java/lang/invoke/MethodHandles$Lookup.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;
  16: astore_0
  17: aload_0
  18: invokevirtual #52    // Method java/lang/invoke/MethodHandle.invokeExact:()I
  21: istore_1
  22: return

Может ли кто-нибудь объяснить это для меня?

1 ответ

Решение

Вы можете заметить, что invokeExact действительно возвращает int из своего дескриптора ()I:

  18: invokevirtual #52    // Method java/lang/invoke/MethodHandle.invokeExact:()I

В результате кастинг не требуется.

Причина, по которой он возвращает intне Objectэто метод invokeExact (так же как invoke) в MethodHandle обрабатываются специально, см. invokeExact API

Возвращает:

сигнатурно-полиморфный результат, статически представленный с использованием Object

и из фирменного полиморфизма:

... Необычной частью является то, что дескриптор символьного типа получен из фактического аргумента и возвращаемого типа, а не из объявления метода.

Другие вопросы по тегам