桥接方法在 java 中用于处理派生方法中的协变,并更改派生方法的可见性。
但是,这两种情况都是针对实例方法(因为您无法派生静态方法)。
我正在研究 Kotlin 如何生成参数默认值,令我震惊的是它使用了static 桥接方法。
我想不出在什么情况下 Javac 会生成static 桥接方法 - 其他人可以吗?(我指的是具有 ACC_BRIDGE 标志的方法(0x40) 集合,不仅仅是一种语义桥接方法)
(fwiw - 示例代码和反编译(使用 cfr 0_124 和 --hidebridgemethods false))
方差
public class BridgeTest1Base<T> {
public T frob() {
return null;
}
}
public class BridgeTest1Derived extends BridgeTest1Base<Integer> {
public Integer frob() {
return null;
}
}
反编译为
public class BridgeTest1Derived extends BridgeTest1Base<Integer> {
@Override
public Integer frob() {
return null;
}
@Override
public /* bridge */ /* synthetic */ Object frob() {
return this.frob();
}
}
可见性
class BridgeTest2Base {
public void frob() {
}
}
public class BridgeTest2Derived extends BridgeTest2Base {}
反编译为
public class BridgeTest2Derived extends BridgeTest2Base {
@Override
public /* bridge */ /* synthetic */ void frob() {
super.frob();
}
}
Kotlin 默认设置 - yum!
class frob2() {
fun fred2(x: Int = 300, y: frob2 = mkFrob2(x)) {
println("{this}{x}{y}")
}
fun mkFrob2(x: Int): frob2 {
return this;
}
fun foobar() {
fred2();
fred2(100);
fred2(100, frob2());
}
}
反编译(到 java)到(注意静态桥)
public final class frob2 {
public final void fred2(int x, @NotNull frob2 y) {
Intrinsics.checkParameterIsNotNull((Object)y, (String)"y");
String string = "{this}{x}{y}";
System.out.println((Object)string);
}
public static /* bridge */ /* synthetic */ void fred2$default(frob2 frob22, int n, frob2 frob23, int n2, Object object) {
if ((n2 & 1) != 0) {
n = 300;
}
if ((n2 & 2) != 0) {
frob23 = frob22.mkFrob2(n);
}
frob22.fred2(n, frob23);
}
@NotNull
public final frob2 mkFrob2(int x) {
return this;
}
public final void foobar() {
frob2.fred2$default(this, 0, null, 3, null);
frob2.fred2$default(this, 100, null, 2, null);
this.fred2(100, new frob2());
}
}
最佳答案
根据 Java 语言规范的桥接方法,应该使用 ACC_BRIDGE
注释的方法,用于确保覆盖兼容签名,以便代码调用使用原始签名的方法将以重写方法结束,即使它在字节码级别具有不同的方法签名。 Java 编程语言中唯一的应用是类型删除和协变返回类型。
由于 static
方法不能以调用者可能被重定向的方式被重写,因此对于 static
方法。因此,javac
永远不会生成具有 ACC_BRIDGE
和 ACC_STATIC
设置的方法。
代表另一种语言的语义将方法标记为桥接方法也是一个非常值得怀疑的行为。作为the JVM specification说:
The
ACC_BRIDGE
flag is used to indicate a bridge method generated by a compiler for the Java programming language.
还有其他可能是static
的合成委托(delegate)方法,例如嵌套类访问器或方法引用的适配器(例如,varargs 或交集类型)。这些不算作桥接方法。
关于java - javac 会生成静态桥接方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48202814/