Рассмотрим следующий набор выражений:
class T {{
/*1*/ super.toString(); // direct
/*2*/ T.super.toString(); // synthetic
Supplier<?> s;
/*3*/ s = super::toString; // synthetic
/*4*/ s = T.super::toString; // synthetic
}}
Что дает следующий результат:
class T {
T();
0 aload_0 [this]
1 invokespecial java.lang.Object() [8]
4 aload_0 [this]
5 invokespecial java.lang.Object.toString() : java.lang.String [10]
8 pop // ^-- direct
9 aload_0 [this]
10 invokestatic T.access$0(T) : java.lang.String [14]
13 pop // ^-- synthetic
14 aload_0 [this]
15 invokedynamic 0 get(T) : java.util.function.Supplier [21]
20 astore_1 [s] // ^-- methodref to synthetic
21 aload_0 [this]
22 invokedynamic 1 get(T) : java.util.function.Supplier [22]
27 astore_1 // ^-- methodref to synthetic
28 return
static synthetic java.lang.String access$0(T arg0);
0 aload_0 [arg0]
1 invokespecial java.lang.Object.toString() : java.lang.String [10]
4 areturn
Bootstrap methods:
0 : # 40 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:...
#43 invokestatic T.access$0:(LT;)Ljava/lang/String;
1 : # 40 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:...
#46 invokestatic T.access$0:(LT;)Ljava/lang/String;
}
Почему строки java code /*2*/
, /*3*/
и /*4*/
производят и используют синтетический метод доступа access$0
? Я бы ожидал, что строки /*2*/
и методы бутстрапа для строк /*3*/
и /*4*/
также будут использовать invokespecial
, как это делает строка /*1*/
.
Особенно, когда метод Object::toString
доступен непосредственно из соответствующей области, например. следующая ссылка метода не переносит вызов синтетического метода доступа:
class F {{
Function<Object, ?> f = Object::toString; // direct
}}
Однако там есть разница:
class O {{
super.toString(); // invokespecial -> "[email protected]"
O.super.toString(); // invokespecial -> "[email protected]"
Supplier<?> s;
s = super::toString; // invokespecial -> "[email protected]"
s = O.super::toString; // invokespecial -> "[email protected]"
Function<Object, ?> f = Object::toString;
f.apply(O.super); // invokeinterface -> "override"
}
public String toString() {return "override";}
}
Что вызывает другой вопрос: существует ли способ обхода переопределения в ((Function<Object, ?> Object::toString)::apply
?