my question is quite theoretic... This is the signature of Class.asSubclass (Javadoc):
public Class extends U> asSubclass(Class clazz)
In case of the return type Class extends U>
. Lets first try understanding, the getClass
signature:
AbstractList ls = new ArrayList<>();
Class extends AbstractList> x = ls.getClass();
Now had the compiler allowed us to do:
Class x = ls.getClass();
This would have been wrong. Because at runtime, ls.getClass
would be ArrayList.class
and not AbstractList.class
. Neither can ls.getClass
return Class
because ls
is of type AbstractList<> and not Arraylist
So the compiler, now says - Ok! I cant return Class
nor can I return Class
. But because I know ls
is an AbstractList for sure, so the actual class object can only be a subtype of AbstractList. So Class extends AbstractList>
is a very safe bet. Because of wild card:
You cannot do:
AbstractList ls = new ArrayList<>();
Class extends AbstractList> x = ls.getClass();
Class> xx = x;
Class> xxx = x;
The same logic applies to your question. say suppose it was declared as:
public Class asSubClass(Class c)
The below would have compiled:
List ls = new ArrayList<>();
Class extends List> x = ls.getClass();
Class aClass = x.asSubclass(AbstractList.class); //BIG ISSUE
Above aClass
at runtime is Class
and not Class
. So this should not be allowed!! Class extends AbstractList>
is the best bet.
The first thought I had on looking at the question was, why wasn't it declared as:
public Class extends U> asSubClass(Class c)
it makes more sense to have a compile time restriction on the arguments I can pass. But the reason I think it was not preferred was - this would have broken the backward compatibility of pre-java5 code. For example, code such as below which compiled with pre-Java5 would no longer compile if it asSubClass
was declared as shown above.
Class x = List.class.asSubclass(String.class); //pre java5
// this would have not compiled if asSubclass was declared above like
Quick check:
public static Class extends U> asSubClaz(Class t, Class c){
return t.asSubClass(c);
}
public static Class extends U> asSubClazOriginal(Class t, Class c){
return t.asSubClass(c);
}
asSubClazOriginal(List.class, String.class);
asSubClaz(List.class, String.class); //error. So would have broken legacy code
PS: For the edited question, on why asSubClass
rather than cast? - Because cast is betrayal. For example:
List ls = new ArrayList<>();
Class extends List> x = ls.getClass();
Class aClass = (Class) x;
Above would always succeed because generics are erased. So its class cast to a class. But aClass.equals(ArrayList.class)
would give false. So definitely cast is wrong. In case you need type safety, you can use asSubClaz
above