В Java 8 появилась поддержка функций первого класса, что позволяет назначать функции переменным. В этом случае переменные должны иметь тип функции, который определяется функциональным интерфейсом (интерфейс только с одним абстрактным методом).
Итак, рассмотрим пример интерфейса I
и класса A
со следующим определением:
interface I{ int foo(); }
class A implements I{
public int foo(){return 7;}
public static int bar(){return 11;}
}
Мы можем присвоить переменной типа I
экземпляр типа A
или ссылку на метод метода bar
типа A
. Оба могут храниться в переменных типа I
, например:
I i1 = new A();
I i2 = A::bar;
Если мы проанализируем байткоды, полученные в результате компиляции предыдущего кода, мы получим:
0: new #2 // class A
3: dup
4: invokespecial #3 // Method A."<init>":()V
7: astore_1
8: invokedynamic #4, 0 // InvokeDynamic #0:foo:()LI;
13: astore_2
Для i1 = new A();
ясно, что соответствующая инструкция 7: astore_1
хранит экземпляр A
, совместимый с I
. Но в результате i2 = A::bar
мы сохраняем результат 8: invokedynamic #4, 0
.
Итак, это означает, что результатом invokedynamic
всегда является экземпляр целевого типа, который является типом переменной, которую мы назначаем со ссылкой на метод?