Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override a method in Java generically

If I have a base class like this that I can't change:

public abstract class A {
    public abstract Object get(int i);
}

and I try to extend it with a class B like this:

public class B extends A{
    @Override
    public String get(int i){
        //impl
        return "SomeString";
    }
}

everything is OK. But my attempt to make it more generic fails if I try:

public class C extends A{
    @Override
    public <T extends Object> T get(int i){
        //impl
        return (T)someObj;
    }
}

I can't think of any reason why this should be disallowed. In my understanding, the generic type T is bound to an Object—which is the requested return type of A. If I can put String or AnyObject as my return type inside B, why am I not allowed to put <T extends Object> T inside my C class?

Another strange behavior, from my point of view, is that an additional method like this:

public class D extends A{

    @Override
    public Object get(int i){
        //impl
    }

    public <T extends Object> T get(int i){
        //impl
    }
}

is also not allowed, with the hint of a DuplicateMethod provided. This one, at least, confuses me, and I think Java should make a decision: if it is the same return type, why not allow overriding; and if it is not, why shouldn't I be able to add this method? To tell me it's the same, but not allow it to be overridden, is very weird, based on common sense.

like image 483
Rafael T Avatar asked Sep 25 '12 08:09

Rafael T


People also ask

Can we override a method in inheritance?

Instance MethodsThe ability of a subclass to override a method allows a class to inherit from a superclass whose behavior is "close enough" and then to modify behavior as needed. The overriding method has the same name, number and type of parameters, and return type as the method that it overrides.

How can you declare an override method?

Rules for method overriding: In java, a method can only be written in Subclass, not in same class. The argument list should be exactly the same as that of the overridden method. The return type should be the same or a subtype of the return type declared in the original overridden method in the super class.

What does an override method do?

Method overriding, in object-oriented programming, is a language feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its superclasses or parent classes. It allows for a specific type of polymorphism (subtyping).


2 Answers

JLS # 8.4.2. Method Signature

The signature of a method m1 is a subsignature of the signature of a method m2 if either:

  • m2 has the same signature as m1, or

  • the signature of m1 is the same as the erasure (§4.6) of the signature of m2.

As per above rule as your parent do not have an erasure and your child has one so it is not a valid overriding.

JLS#8.4.8.3. Requirements in Overriding and Hiding

Example 8.4.8.3-4. Erasure Affects Overriding

A class cannot have two member methods with the same name and type erasure:

class C<T> {     T id (T x) {...} } class D extends C<String> {     Object id(Object x) {...} } 

This is illegal since D.id(Object) is a member of D, C.id(String) is declared in a supertype of D, and:

  • The two methods have the same name, id
  • C.id(String) is accessible to D
  • The signature of D.id(Object) is not a subsignature of that of C.id(String)
  • The two methods have the same erasure

Two different methods of a class may not override methods with the same erasure:

 class C<T> {      T id(T x) {...}  }  interface I<T> {      T id(T x);  }  class D extends C<String> implements I<Integer> {     public String  id(String x)  {...}     public Integer id(Integer x) {...}  } 

This is also illegal, since D.id(String) is a member of D, D.id(Integer) is declared in D, and:

  • The two methods have the same name, id
  • D.id(Integer) is accessible to D
  • The two methods have different signatures (and neither is a subsignature of the other)
  • D.id(String) overrides C.id(String) and D.id(Integer) overrides I.id(Integer) yet the two overridden methods have the same erasure

Also It gives example of a case where it is allowed from super to child

The notion of subsignature is designed to express a relationship between two methods whose signatures are not identical, but in which one may override the other. Specifically, it allows a method whose signature does not use generic types to override any generified version of that method. This is important so that library designers may freely generify methods independently of clients that define subclasses or subinterfaces of the library.

Consider the example:

class CollectionConverter { List toList(Collection c) {...} } class Overrider extends CollectionConverter {  List toList(Collection c) {...} 

}

Now, assume this code was written before the introduction of generics, and now the author of class CollectionConverter decides to generify the code, thus:

 class CollectionConverter {    <T> List<T> toList(Collection<T> c) {...}  } 

Without special dispensation, Overrider.toList would no longer override CollectionConverter.toList. Instead, the code would be illegal. This would significantly inhibit the use of generics, since library writers would hesitate to migrate existing code.

like image 154
Amit Deshpande Avatar answered Sep 30 '22 17:09

Amit Deshpande


Well, for the first part, the answer would be that Java does not allow non-generic methods to be overridden by generic methods, even if the erasure is the same. It means that it wouldn't work even if you would just have the overriding method as:

 public <T extends Object> Object get(int i)

I don't know why Java poses this limitation (gave it some thought), I just think it has to do with special cases implemented for sub-classing generic types.

Your second definition would essentially translate to:

public class D extends A{

    @Override
    public Object get(int i){
    //impl
    }

    public Object get(int i){
        //impl
    }

}

which is obviously a problem.

like image 45
Tudor Vintilescu Avatar answered Sep 30 '22 16:09

Tudor Vintilescu