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

时间:2015-12-21 18:05:54

标签: java generics

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

}

目的是不是一样的?

3 个答案:

答案 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);
}