简体   繁体   中英

Overriding a method using type erasure

Today I stumbled upon something interesting. Assume the following Java 6 class:

public class Ereasure {

    public Object get(Object o) {
        return null; // dummy
    }

    public  static class Derived<T> extends Ereasure{
        // (1)
        @Override
        public Object get(T o) {
                return super.get(o);
        }
        // (2)
        /*
        @Override
        public Object get(Object o) {
                return super.get(o);
        }*/

    }
}

If you try to compile the above example, the compiler says Ereasure.java:9: method does not override or implement a method from a supertype @Override If you remove the @Override annotation(which should not be necessary!), it says Ereasure.java:8: name clash: get(T) in Ereasure.Derived and get(java.lang.Object) in Ereasure have the same erasure, yet neither overrides the other This is a bit contradictional, since T should erease to Object and therefor override the parent classes get method.

If you leave (1) unannotated and uncomment (2) so (1) overloads (2) it would not work either. Compiler output:

Ereasure.java:15: get(T) is already defined in Ereasure.Derived
  public Object get(Object o) {

As a conclusion, T is being ereased to Object, but cannot override the parent get Method.

My question is now, why dooesn't at least one of the examples compile?

You can see in the example below why it is impossible to do what you want:

public class Erasure {

   public void set(Object o) {
      return;
   }

   // method overloading: (which is valid)
   public void set(String s) {
      return;
   }

   public static class Derived<S> extends Erasure {

      // Oops... which one am I supposed to override?
      // (It would actually be overloading if S was a concrete type
      // that is neither Object nor String.)
      @Override
      public void set(S o) { // does not compile
         super.set(o);
      }
   }
}

The solution to your problem is that Erasure should be a parameterized class.

At a simple guess the compiler does not use the generic view when calculating overloads which of course would not make sense, because sometimes T might be Object other times its another type. The overridding would then become dependent on a moving target T which is downright wrong, especially if there were multiple methods all called "get" but with different single parameter types. In such a case it just wouldnt make sense and at a guess they chose to just keep things simple.

Consider a case where you have both a getter and a setter overridden as generics.

Derived<String> d = new Derived<String();
Erasure e = d;
e.set(new Object());
String s = d.get(); //Class cast exception

The fundamental principal of generics is that a class cast exception can only happen if there is either (a) an explicit cast or (b) a warning. If you were allowed to do what you wanted, the above would throw an exception without either.

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