对于以下情况,假设AModel.class扩展了ABCModel,案例1
案例1有效
public static Class<? extends ABCModel> getModel(String objectModel) {
if(objectModel.equalsIgnoreCase("")) {
return AModel.class;
}
return null;
}
案例2(抛出编译错误)
public static <T extends ABCModel> Class<T> getModel(String objectModel) {
if(objectModel.equalsIgnoreCase("")) {
return AModel.class;
}
return null;
}
目的是不是一样的?
答案 0 :(得分:3)
在第二种情况下,您将约束类型变量T
以扩展ABCModel
并承诺返回Class<T>
。但是,T
并未绑定到任何地方,因此在编译期间无法确定T
是什么。
示例1的不同之处在于返回类型定义为Class<? extends ABCModel>
,其上限为ABCModel
。
在第二种情况下,在编译时绑定T
的一种方法是将其作为方法的参数,例如:
public static <T extends ABCModel> Class<T> getModel(String objectModel, Class<T> clazz) {
现在T
基于传递给方法的参数进行绑定(这就是为什么你会看到很多通用方法接受Class
参数)。
当然,这对你的方法没有帮助,因为你想要检索Class
,如果你已经让它传入,这是不必要的。但这只是意味着你应该使用示例1或修理你的设计。
答案 1 :(得分:1)
这两者非常不同。
在第一种情况下,您将返回扩展ABCModel
的某个类,即您决定。调用者不能假设类型参数的身份。
在第二种情况下,您承诺返回班级T
,无论调用者想要什么T
!调用者可以调用您的方法,T
无论他们想要什么,并且您的方法必须神奇地返回该类型参数的类,在这种情况下,不知道T
是的。这意味着您的方法必须使用相同的代码同时返回Class<AModel>
和Class<BModel>
等。这显然是不可能的(除非它总是返回null
)。
答案 2 :(得分:1)
问题的解决方案取决于您的使用案例:
如果您的方法确定了特定类型并将其返回,那么您的第一个示例就是正确的方法。尝试进一步指定返回类型是没有用的,因为问题&#34;哪个子类型&#34;如果调用者需要指定该类型,则无法回答。
但是,如果您的方法有多个调用,并且每个调用都将返回预期的子类型,则泛型返回类型很有用。在这种情况下,您的调用者将知道特定的返回类型,并可以使用该参数来避免在调用站点上进行强制转换。您需要做的就是在您的实现中包含该演员:return (Class<T>) AModel.class;
第一个案例:
// The caller does not know the return type, so a simple unknown type is appropriate
Class<?> determineType(Object myObject) {
return myObject.getClass();
}
第二个案例:
// The caller will already know that a property named 'street' will be of type String, so he can invoke <String>getTypedProperty("street") and avoid having to cast himself
<T> T getTypedProperty(String name) {
return (T) genericPropertyStore.get(name);
}