java - 为什么在这种情况下删除通用类型会阻止覆盖?

标签 java generics inheritance

以下代码无法在 OpenjDK 11 上编译。 在我看来,B 中的 test1 应该覆盖 A 中的 test1,因为:

  1. 这些方法具有相同的名称。
  2. 这些方法具有相同的参数列表。
  3. 这些方法具有相同的可见性。
  4. 这些方法实际上不会抛出可能不兼容的已检查异常。
  5. 它们的返回类型是协变的。

我拿了一个反编译器,分别反编译了每个类。编译后的代码实际上如我所料地工作。它将 U extends Number 替换为 Number,T extends Integer 替换为 Integer 等等。但是当我尝试将这两个类编译在一起时,我在第二个类上遇到错误,表明第二个类中的测试没有覆盖第一个类中的方法。

我在这里遗漏了一些或大或小的东西。它可能与 5 有关。也许类型不是协变的。你能帮帮我吗?

class A {
    <U extends Number, T extends Number> U test(T test) {
        System.out.println("In A.test(T test)");
        return null;
    }
    //Decompiler shows that the above method erases to 
    // Number test(Number test)
    // Just like the method below.
        
    Number test2(Number test) {
        return null;
    }
}

class B extends A {
    //Unsuccessful override. Compiler error.
    @Override  
    <U extends Integer, T extends Number> U test(T test) {
        System.out.println("In B.test(T tesT)");
        return null;
    }
    //Decompiler shows that the above method erases to 
    //Integer test(Number test)
    //Just like the method bellow.
    
    
    //Successful override
    @Override
    Integer test2(Number test) {
        return null;
    }
}

最佳答案

您的 test 方法产生错误的原因是它们具有完全不相关的不同签名。请注意 signature一个方法由它的名称、参数列表、和类型参数组成。

引自 Java 语言规范:

Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the type parameters of M, the same formal parameter types.

至关重要的是,您的两个 test 方法没有 same type parameters ,因为 A.test 中的 UB.testU 有不同的 bound.

Two methods or constructors M and N have the same type parameters if both of the following are true:

  • M and N have same number of type parameters (possibly zero).

  • Where A1, ..., An are the type parameters of M and B1, ..., Bn are the type parameters of N, let θ=[B1:=A1, ..., Bn:=An]. Then, for all i (1 ≤ i ≤ n), the bound of Ai is the same type as θ applied to the bound of Bi.

想想如果 B.test 实际上覆盖了 A.test 会发生什么。您可以将类型传递给超出其范围的类型参数 U!

A a = new B();
// This will call B.test, and U is Double, T is Integer
// but U should extends Integer!
Double x = a.test((Integer)0); 

欲了解更多信息,here是何时发生覆盖的精确规则。请注意,实际上并未考虑您列表中的条件#4 和#5。它们只是额外的要求,如果您破坏它们,它们会使您的代码无法编译。即使您违反了这些要求,一种方法仍被“定义”为覆盖另一种方法。它们被列为 here在 JLS 中。

关于java - 为什么在这种情况下删除通用类型会阻止覆盖?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70607154/

相关文章:

javascript - 将原型(prototype)添加到 JSON 字符串中的所有对象

java - 从 Math.cos() 输出值获取输入 float

java - 生产期间的 Logcat

C# 泛型方法返回值

java - FlexJson 序列化和反序列化接口(interface)

Codeigniter 多级继承

java - 如何从 NetBeans 中删除 "Java support"?

java - 连接到在 docker 容器上运行的远程 activemq 实例

generics - 无法访问动态特征实现中的结构字段

java - 理解Java new Class[]数组和实现