接受通用通配符,但不接受类型T



对于以下情况,假设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;
}

目的不只是一样吗?

在第二种情况下,您将约束类型变量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或修复你的设计。

两者非常不同。

在第一种情况下,您将返回某个扩展ABCModel类,由您决定。调用方不能假定任何关于类型参数标识的信息。

在第二种情况下,您承诺返回类T,无论调用方想要什么T!调用者可以调用T的方法,而不管它想要什么,并且您的方法必须神奇地返回该类型参数的类,在这种情况下,根本不知道T是什么。这意味着您的方法必须同时返回具有相同代码的Class<AModel>Class<BModel>等。这显然是不可能的(除非它总是返回null)。

问题的解决方案取决于您的用例:

如果您的方法确定了一个特定类型并返回它,那么您的第一个示例就是正确的方法。尝试进一步指定返回类型是没有用的,因为如果调用方需要指定返回类型,则无法回答"哪个子类型"的问题。

但是,如果您的方法有多个调用,并且每个调用都将始终返回所需的子类型,则泛型返回类型非常有用。在这种情况下,调用者将知道特定的返回类型,并可以使用该参数来避免在调用站点上进行强制转换。您所需要做的就是在您的实现中包括转换: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);
}