Java Generics - 方法覆盖

时间:2015-03-27 08:32:58

标签: java generics

我有一对班级ClassA& ClassB如下所示。
案例1:

class ClassA<T extends Number>{
    void method(T t){}
}

class ClassB extends ClassA<Integer>{
    @Override
    void method(Integer i){}
}

案例2:

class ClassA{
    void method(Number t){}
}

class ClassB extends ClassA{
    @Override
    void method(Integer i){}
}

我这里有两个问题 [Q1] 我说对了,case2是case1的运行时表示(在类型擦除之后)?

[Q2] 如果我对[q1]是正确的,那么为什么case1被接受为有效覆盖? (我知道为什么case2不是有效覆盖,因为参数不相同。)

有人请对此有所了解。 提前谢谢。

3 个答案:

答案 0 :(得分:19)

[q1]的答案是否定的。 编译器将在ClassB中生成实际上覆盖method(Number) bridge 方法。

class ClassB extends ClassA{
    // bridge method
    void method(Number i){
        method((Integer)i);
    }

    void method(Integer i){}
}

您将在java doc类型擦除中获得完整的答案。

答案 1 :(得分:1)

在Java中(从版本5开始),重写方法的返回类型必须是协变的,并且重写方法的参数必须是逆变的。

这意味着覆盖类可以更具体地返回它所接收的内容,并且更接受它所接收的内容。

在您的第二个示例中,假设ClassA类型的变量,其中ClassB的实例为值。

 ClassA a = new ClassB(); // This is legal, since ClassB is a subclass of ClassA
 a.method(1.0); // This is legal, since ClassA.method accepts Number

然而另一种方式是可以的:

public class ClassC { public Number method(Integer i) {...} }
public class ClassD extends ClassC {
   @Override 
   public Integer method(Number n) {...}
}

有效,因为ClassD仍然符合ClassC定义的合同。

答案 2 :(得分:0)

ClassB的实际超类是ClassA<Integer>。因此,其成员函数method具有编译时签名:

void method(Integer t){}

你可以通过调用类似

之类的东西来说服自己
ClassA a = new ClassB();
a.method(1.0);

您应该会看到运行时错误。实际上只能编译它,因为我使用了ClassA的擦除版本。实际上每个任务都分配到了 ClassA<Integer>以外的泛型类型(例如ClassA<Number&gt;)会因类型不兼容而失败。