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>forgetMainClass()from the typeSubFooneeds unchecked conversion to conform toClass<Interface>from the typeSuperFoo
Doesn't Class<Implementation> fall under 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With