开发者

Overriding method with generic return type

开发者 https://www.devze.com 2023-02-13 18:26 出处:网络
Let\'s say I have a super-class that defines the following abstract method public abstract <T extends Interface> Class<T> getMainClass();

Let's say I have a super-class that defines the following abstract method

public abstract <T extends Interface> Class<T> getMainClass();

Now if I want to override it in some sub-class

public Class<Implementation> getMainClass(){
    return Implementation.class;
}

I get a warning about type safety and unchecked conversion:

Type safety: The return type Class<Implementation> for getMainClass() from the type SubFoo needs unchecked conversion to conform to Class<Interface> from the type SuperFoo

Doesn't Class<Implementation> fall u开发者_StackOverflow社区nder Class<T> if <T extends Interface>? Is there any way to properly get rid of the warning?


the overriding method's return type must be a subtype of the overridden method's return type.

Class<Impl> is not a subtype of Class<T> where <T extends Interface>. T is unknown here.

Class<Impl> is a subtype of Class<? extends Interface>, per subtyping rules.


some subtyping rules regarding wildcards:

for any type X

  • A<X> is a subtype of A<? extends X>

  • A<X> is a subtype of A<? super X>

if S is subtype of T

  • A<? extends S> is a subtype of A<? extends T>

  • A<? super T> is a subtype of A<? super S>

More concisely, ( <: means "is a subtype of" )

A<S>    <:    A<? extends S>    <:    A<? extends T>

A<T>    <:    A<?  super  T>    <:    A<?  super  S>


Consider the following scenario similar to yours:

public class SuperFoo {
     public abstract <T extends Interface> List<T> getList();
} 

public class SubFoo extends SuperFoo {
     private List<Implementation> l = new ArrayList<Implementation>();

     public List<Implementation> getList() {
          return l;
     }

     public void iterate() {
          for (Implementation i: l) ...;
     }
}

SubFoo subFoo = new SubFoo();
SuperFoo superFoo = subFoo;
superFoo.getList().add(new AnotherImplementation()); // Valid operation!
subFoo.iterate(); // Unexpected ClassCastException!

In this case unchecked conversion warning warns you about possibility of unexpected ClassCastException.

However, in your case, when return type is Class<...>, it's not a problem (as far as I understand), so you can legally suppress a warning:

@SuppressWarnings("unchecked")
public Class<Implementation> getMainClass(){ ... }  

Another option is to make SuperFoo itself generic:

public class SuperFoo<T extends Interface> {
    public abstract Class<T> getMainClass(); 
}

public class SubFoo extends SuperFoo<Implementation> {
    public Class<Implementation> getMainClass() { ... }
}

For yet another (and perhaps the best) option see Stas Kurilin's answer.


try this

public abstract Class<? extends Interface> getMainClass();

reorganized example by such warnings java tried prevents cases like this

class OtherImpl implements Interface{ 
} 
A a = new B();//where A - your abstract class and B - implementation
Class<OtherImpl> other = a.<OtherImpl>getMainClass();//some broken think, But _without_ runtime exception

As @axtavt mentioned example was broken. I reorganized it.


Why do you want to have something like public abstract Class<? extends Interface> getMainClass(); rather than public abstract Interface getMainClass();?

I think you can simply return an instance of Interface, and then, if the caller wants to have access to the underlying runtime class can simply call getClass() on the returned object.

Essentially, I think you can simply do

public InterfaceImpl implements Interface {
    // ...
};

public abstract class A {
    public abstract Interface getMainClass();
    // ...
}

public class AImpl {
    return new InterfaceImpl();
}

public class Main {
    public static void main(String[] args) {
        AImpl aImpl = new AImpl();
        Interface i = aImpl.getMainClass();
        System.out.println(i.getClass());
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消