java - javac 会生成静态桥接方法吗?

标签 java jvm decompiling

桥接方法在 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_BRIDGEACC_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/

相关文章:

包含私有(private)调用的 Java 内联方法

c - 了解反编译汇编代码

Java 正则表达式 : Match any words word and must contain a certain work but except one word

java - 在java中增加和减少一个变量直到达到一个数字

java - 使用 javax.validation.Validator 等时出现的问题

java - ConcurrentGCThread 中 Java VM 的随机崩溃

java - 无法使用 ServerSocket.socketBind 分配请求的地址

c - Ghidra 是否误解了函数调用?

android - 是否可以从命令行使用 Android Studio 的反编译器?

java - 如何删除之前创建的 JLabel?