简体   繁体   中英

Java Generics - Method overriding

I have a pair of classes ClassA & ClassB as shown below.
case 1:

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

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

case 2:

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

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

I have two questions here.
[q1] Am I right if I say that, case2 is the runtime representation of case1(after type erasure)?

[q2] If I am right about [q1], then why the case1 is accepted as a valid override? (I know why case2 is not a valid override since the parameters are not same.)

Someone please shed some light on this. Thanks in advance.

The answer to [q1] is no. The compiler will generate a bridge method in the ClassB that will actually overide the method(Number) .

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

    void method(Integer i){}
}

You will have the complete answer in the java doc on type erasure.

In Java (since version 5) the return types of an overridden methods have to be covariant and the parameters of the overridden methods have to be contravariant.

That means that the overriding class can be more specific in what it returns and more accepting in what it receives.

In your 2nd example imagine a variable of the type ClassA with an instance of the ClassB as a value.

 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

The other way however would be ok:

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

is valid, because the ClassD still fulfills the contract defined by ClassC .

The actual superclass of ClassB is ClassA<Integer> . Therefor its member function method has the compile-time signature:

void method(Integer t){}

You can convince yourself by invoking something like

ClassA a = new ClassB();
a.method(1.0);

You should see a runtime error. In fact it is only possible to compile this, because I used the erased version of ClassA . In fact every assignment to a generic type other than ClassA<Integer> (eg ClassA<Number >) would fail due to incompatible types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM