简体   繁体   English

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

[英]generic wildcard is accepted but not Type T

For below cases, assuming AModel.class extends ABCModel, The case 1 对于以下情况,假设AModel.class扩展了ABCModel,则情况1

case 1 works 案例1有效

public static Class<? extends ABCModel> getModel(String objectModel) {

                if(objectModel.equalsIgnoreCase("")) {
                    return AModel.class;
                }

    return null;

    }

case 2 (throws compilation error) 情况2(引发编译错误)

public  static <T extends ABCModel> Class<T> getModel(String objectModel) {

            if(objectModel.equalsIgnoreCase("")) {
                return AModel.class;
            }

return null;

}

Is the purpose is not just the same ? 目的不只是一样吗?

In the second case you're constraining the type variable T to extend ABCModel and promising to return Class<T> . 在第二种情况下,您将约束类型变量T来扩展ABCModel并承诺返回Class<T> However the T doesn't get bound anywhere, so during compile-time there's no way to determine what T is. 但是T不会在任何地方绑定,因此在编译时无法确定T是什么。

The difference in example 1 is that the return type is defined to be Class<? extends ABCModel> 示例1的不同之处在于返回类型定义为Class<? extends ABCModel> Class<? extends ABCModel> , which has an upper bound of ABCModel . Class<? extends ABCModel> ,其上限为ABCModel

One way to bind T during compile-time in your second case is to give it as a parameter to the method, for example: 在第二种情况下,在编译时绑定T一种方法是将其作为方法的参数,例如:

public static <T extends ABCModel> Class<T> getModel(String objectModel, Class<T> clazz) {

Now T is bound based on the parameter passed into the method (which is why you see a lot of generic methods taking in a Class parameter). 现在, T是根据传递给方法的参数进行绑定的(这就是为什么您看到许多使用Class参数的通用方法的原因)。

Of course this won't help with your method since you want to retrieve the Class , which is unnecessary if you already have it to pass in. But that just means that you should either use example 1 or fix your design. 当然,这对您的方法无济于事,因为您想要检索Class ,如果您已经将其传递进来,则没有必要。但这仅意味着您应该使用示例1或修复您的设计。

The two are very different. 两者有很大的不同。

In the first case, you are returning some class that extends ABCModel , that you decide . 在第一种情况下,你将一些类,它扩展ABCModel你决定 The caller cannot assume anything about the identity of the type parameter. 调用者不能假定有关类型参数的身份的任何信息。

In the second case, you are promising to return the class T , for whatever T the caller wants! 在第二种情况下,您保证将返回T类,无论调用者想要什么T The caller can call your method with T being whatever it wants , and your method has to magically return a class of that type parameter, in this case, without knowing what T is at all. 调用者可以使用您想要的 T来调用您的方法,在这种情况下,您的方法必须神奇地返回该类型参数的类,而根本不知道T是什么。 That means your method must simultaneously return a Class<AModel> and Class<BModel> , etc. with the same code. 这意味着您的方法必须同时返回具有相同代码的Class<AModel>Class<BModel>等。 That is clearly impossible (unless it always returns null ). 这显然是不可能的(除非它总是返回null )。

The solution to your problem depends on your use case: 解决问题的方法取决于您的用例:

If your method determines a specific type and returns it, your first example is the correct approach. 如果您的方法确定了特定类型并返回了它,则第一个示例就是正确的方法。 There is no use trying to specify the return type further, as the question "Which subtype" cannot by answered if the caller needs to specify that type. 尝试进一步指定返回类型没有用,因为如果调用者需要指定该类型,则无法回答问题“哪个子类型”。

If however, there are several invocations of your method, and each of those will always return the expected subtype, the generic return type is useful. 但是,如果您的方法有多个调用,并且每个调用将始终返回期望的子类型,则通用返回类型很有用。 In that case, your caller will know the specific return type and can use the parameter to avoid a cast on the calling site. 在这种情况下,您的呼叫者将知道特定的返回类型,并可以使用该参数来避免在呼叫站点上进行强制转换。 All you need to do is include that cast in your implementation: return (Class<T>) AModel.class; 您需要做的就是在实现中进行转换: return (Class<T>) AModel.class;

First case example: 第一种情况示例:

// The caller does not know the return type, so a simple unknown type is appropriate
Class<?> determineType(Object myObject) {
  return myObject.getClass(); 
}

Second case example: 第二种情况示例:

// 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM