gpt4 book ai didi

java - 用子类作为参数和泛型覆盖 : where is it in Java Lang Spec?

转载 作者:搜寻专家 更新时间:2023-11-01 02:18:22 26 4
gpt4 key购买 nike

我遇到过类似如下的 Java 代码:

public interface BaseArg {
}

public class DerivedArg implements BaseArg {
}

public abstract class Base <A extends BaseArg> {

A arg;

void doIt() {
printArg(arg);
}

void printArg(A a) {
System.out.println("Base: " + a);
}

}


public class Derived extends Base<DerivedArg> {

void printArg(DerivedArg a) {
System.out.println("Derived: " + a);
}


public static void main(String[] args) {
Derived d = new Derived();
d.arg = new DerivedArg();
d.doIt();
}

}

(随意将其拆分为文件并运行)。

此代码最终会调用 Derived printArg。我意识到这是唯一合乎逻辑的事情。但是,如果我手动对通用 Base 执行“删除”,将所有出现的 A 替换为 BaseArg,覆盖就会崩溃。我现在得到了 Base 版本的 printIt。

似乎“删除”并不完全——不知何故 printArg(A a) 与 printArg(BaseArg a) 不同。我在语言规范中找不到任何依据...

我在语言规范中遗漏了什么?这不是很重要,但它让我很烦 :)。

最佳答案

请注意派生方法调用。问题是为什么,考虑到他们删除的签名不是覆盖等效的。

在编译 Derived 类时,编译器实际上发出了两个方法:方法 printArg(DerivedArg) 和一个合成方法 printArg(BaseArg),它以即使不了解类型参数的虚拟机也能理解的方式覆盖父类(super class)方法,并且委托(delegate)给 printArg(DerivedArg)。您可以通过在 printArt(DerivedArg) 中抛出异常来验证这一点,同时在 Base 类型的引用上调用它,并检查堆栈跟踪:

Exception in thread "main" java.lang.RuntimeException
at Derived.printArg(Test.java:28)
at Derived.printArg(Test.java:1) << synthetic
at Base.doIt(Test.java:14)
at Test.main(Test.java:39)

至于在 Java 语言规范中找到这个,我首先也错过了它,因为它并没有像人们可能期望的那样指定讨论覆盖或子签名关系的地方,而是在“参数化类型的成员和构造函数”中(§4.5.2) ,这表明在检查覆盖等效性之前,父类(super class)的形式类型参数在语法上被子类中的实际类型参数替换。

也就是说,覆盖等效性不受删除的影响,这与流行的假设相反。

关于java - 用子类作为参数和泛型覆盖 : where is it in Java Lang Spec?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1863276/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com