如果返回类型Class<? extends U>
。让我们首先尝试理解,getClass
签名:
AbstractList<String> ls = new ArrayList<>();
Class<? extends AbstractList> x = ls.getClass();
现在编译器允许我们这样做:
Class<AbstractList> x = ls.getClass();
这是错误的。因为在运行时,ls.getClass
将会ArrayList.class
and not AbstractList.class
。也不可以ls.getClass
return Class<ArrayList>
因为ls
是 AbstractList 类型,而不是 Arraylist
所以编译器现在说 - 好的!我回不去Class<ArrayList>
我也不能回来Class<AbstractList>
。但因为我知道ls
肯定是一个 AbstractList,因此实际的类对象只能是 AbstractList 的子类型。所以Class<? extends AbstractList>
是一个非常安全的选择。由于通配符:
你cannot do:
AbstractList<String> ls = new ArrayList<>();
Class<? extends AbstractList> x = ls.getClass();
Class<ArrayList<?>> xx = x;
Class<AbstractList<?>> xxx = x;
同样的逻辑也适用于你的问题。假设它被声明为:
public <U> Class<U> asSubClass(Class<U> c)
下面将编译:
List<String> ls = new ArrayList<>();
Class<? extends List> x = ls.getClass();
Class<AbstractList> aClass = x.asSubclass(AbstractList.class); //BIG ISSUE
Above aClass
在运行时是Class<Arraylist>
并不是Class<AbstractList>
。所以这是不应该允许的!!Class<? extends AbstractList>
是最好的选择。
我看到这个问题时的第一个想法是,为什么不将其声明为:
public <U extends T> Class<? extends U> asSubClass(Class<U> c)
对我可以传递的参数进行编译时间限制更有意义。但我认为它不是首选的原因是 - 这会破坏 java5 之前代码的向后兼容性。例如,使用 Java5 之前版本编译的代码(如下所示)将不再编译:asSubClass
已声明如上所示。
Class x = List.class.asSubclass(String.class); //pre java5
// this would have not compiled if asSubclass was declared above like
快速检查:
public static <T, U extends T> Class<? extends U> asSubClaz(Class<T> t, Class<U> c){
return t.asSubClass(c);
}
public static <T, U> Class<? extends U> asSubClazOriginal(Class<T> t, Class<U> c){
return t.asSubClass(c);
}
asSubClazOriginal(List.class, String.class);
asSubClaz(List.class, String.class); //error. So would have broken legacy code
PS:对于编辑过的问题,为什么asSubClass
而不是演员? - 因为演员就是背叛。例如:
List<String> ls = new ArrayList<>();
Class<? extends List> x = ls.getClass();
Class<AbstractList> aClass = (Class<AbstractList>) x;
上面总是会成功,因为泛型被删除了。所以它的类强制转换为一个类。但aClass.equals(ArrayList.class)
会给出错误。所以演员肯定是错误的。如果您需要类型安全,您可以使用asSubClaz
above