Overriding Methods from Non-Generic Supertype – Generics

Overriding Methods from Non-Generic Supertype

In Example 11.13, the signature at (1′) is the same as the signature at (1): set(Integer). The signature at (2′) is the same as the erasure of the signature at (2): set(List). The method at (2′) shows a non-generic subtype method overriding a supertype method that uses generics. This is needed for legacy code: Legacy supertypes can be generified without it having consequences for any subtypes, as the signature of a subtype method that overrides a supertype method will be the same as the erasure of the signature of this supertype method.

Example 11.13 Subsignatures

Click here to view code image

import java.util.List;
class SupA {
  public void set(Integer ref)        {/*…*/}    // (1)
  public void set(List<Integer> list) {/*…*/}    // (2)
}
class SubA extends SupA {
  @Override public void set(Integer ref) {/*…*/}  // (1′) same as at (1)
  @Override public void set(List list) {/*…*/}// (2′) same as the erasure at (2)
}

Overriding Methods from Generic Supertype

In Example 11.14, both the subclasses SubB1 and SubB2 are subtypes of the parameterized supertype SupB<Number>—that is, T is Number in SupB<T>. At compile time, the signatures of the methods in SubB1 are the same as the signatures of the methods in SupB; therefore, the methods are overridden. After erasure, the methods in SupB are equivalent to:

Click here to view code image

public void set(Object t) {/*…*/}               // (1)
public Object get()       {return null;}          // (2)

The compiler adds the following bridge method in SubB1 in order for overriding to work properly at runtime:

Click here to view code image

public void set(Object t) {set((Number)t);}       // (1′)

It does not add a bridge method for the get() method in SubB1 because of covariant return: The return type Number for the method get() in SubB1 is a subtype of the return type Object of the method get() in SupB.

Example 11.14 Overriding from Generic Supertype

Click here to view code image

class SupB<T> {
  public void set(T t) {/*…*/}                  // (1)
  public T get()       {return null;}             // (2)
}
class SubB1 extends SupB<Number> {
  @Override public void set(Number num) {/*…*/} // (1a) Overrides
  @Override public Number get()       {return 0;} // (2a) Overrides
}
class SubB2 extends SupB<Number> {
  @Override public void set(Object obj) {/*…*/} // (1b) Error: same erasure
  @Override public void set(Long l)     {/*…*/} // (1c) Error: overloads

  @Override public Object get() {          // (2b) Error: incompatible return type
    return null;
  }
}

We now examine the methods in SubB2. The set() method at (1b) has the same signature as the erasure of the signature of the set() method at (1) in the supertype SupB. If overriding were allowed, the bridge method added would result in two methods with the same signature set(Object) in SubB2. Two methods with the same signature are not permitted in the same class—called a name clash—therefore, (1b) is not allowed.

The method set() at (1c) is overloaded because its signature is different from the other set() methods in SubB2 and SupB. It would compile if the @Override annotation was removed. The method get() at (2b) has the return type Object, while the get() method in SupB<Number> has the return type Number. The return types are not covariant, and (2b) is rejected.

Example 11.15 shows a typical error where a generic supertype is extended, but its parameterization is missing in the extends clause of the subtype, as shown at (2). The set() method in SubZ neither overrides nor overloads the method at (1). Both methods have the same signature after erasure: set(Object). Adding a bridge method in SubZ to make the overriding work properly would result in a name clash. (1a) is rejected.

Example 11.15 Missing Supertype Parameterization

Click here to view code image

class SupZ<T> {
  public void set(T t) {/*…*/}            // (1)
}
class SubZ<E> extends SupZ {                // Superclass not parameterized
  @Override public void set(E e) {/*…*/}  // (1a) Error: same erasure
}

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *