Class.asSubclass签名 [英] Class.asSubclass signature
问题描述
我的问题很理论......这是Class.asSubclass的签名( Javadoc ):
public< U>类< ;?延伸U> asSubclass(Class< U> clazz)
为什么在返回类型中使用通配符泛型?根据我对泛型的理解,更好的签名可能是:
pre $ public 类< U> asSubclass(Class< U> clazz)
因为您可以确保投射
Class <?延伸U>
更简单
类< U>
Bloch在他的书Effective Java推荐书中(第137页,第28项):
不要使用通配符类型作为返回类型。它不会为您的用户提供额外的灵活性,而是会强制他们在客户端代码中使用通配符类型。
这种选择背后的原因是什么?我错过了什么?
非常感谢您提前。
编辑: MAYBE它已被添加以避免在特定情况下未经检查的转换:当您传递asSubclass方法的结果<直接到另一个方法请求约束类型参数,如下所示(摘自Effective Java,第146页): 以上方法的签名是: 在我看来,asSubclass方法只是一种做法(事实上!)未经检查没有一个适当的编译器警告投掷... 而这最终重新提出我以前的问题:签名 会同样有效(即使奇怪,我承认它) !它将完全兼容getAnnotation示例,并且不会限制客户端代码强制它使用毫无意义的通配符泛型。 Edit2: 如果返回类型为 现在编译器允许我们这样做: 这可能是错误的。因为在运行时, 所以编译器现在说 - Ok!我不能返回 同样的逻辑适用于您的问题。假设它被宣布为: 以下代码可以编译: 在运行时上方 对参数进行编译时限制更有意义我可以通过。但是我认为这不是首选的原因 - 这会破坏java5之前的代码的向后兼容性。例如,如果下面的代码(如下面的代码)使用pre-Java5编译,如果 快速检查: PS:对于编辑的问题,为什么 因为泛型被删除,所以上面的代码总是会成功的。所以它的类投给了一个类。但是 my question is quite theoretic... This is the signature of Class.asSubclass (Javadoc): Why are wildcard generics used in the return type? From my understanding of generics a better signature could be: because you can for sure cast to a more simple Bloch in his book "Effective Java" recommends (page 137, item 28): Do not use wildcard types as return types. Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code. What is the reason behind this choice? What I'm missing?
Thank you very much in advance. Edit:
As @egelev suggests, I could have indeed phrased my question in another manner... in fact returning the input parameter "as is" would be meaningless. So the real problem is:
What is the real usefulness of the Class.asSubclass method, compared to a normal cast? Both would throw a ClassCastException in case of cast problems. MAYBE it has been added to avoid unchecked casting in a specific situation: when you pass the result of the asSubclass method directly to another method asking for a constrained type parameter, as here (taken from Effective Java, page 146): The signature of the above method is: It seems to me that the asSubclass method is only a way to do an (in fact!) unchecked cast without a proper compiler warning... And this in the end re-propose my former question: the signature would be equally effective (even if strange, I admit it)! It would be fully compatible with the getAnnotation example, and would not constrain client code forcing it to use pointlessly wildcard generics. Edit2:
I think my general question has been solved; thank you very much. If someone has other good examples about the correctness of the asSubclass signature please add them to the discussion, I would like to see a complete example using asSubclass with my signature and evidently not working. In case of the return type Now had the compiler allowed us to do: This would have been wrong. Because at runtime, So the compiler, now says - Ok! I cant return The same logic applies to your question. say suppose it was declared as: The below would have compiled: Above The first thought I had on looking at the question was, why wasn't it declared as: it makes more sense to have a compile time restriction on the arguments I can pass. But the reason I think it was not preferred was - this would have broken the backward compatibility of pre-java5 code. For example, code such as below which compiled with pre-Java5 would no longer compile if it Quick check: PS: For the edited question, on why Above would always succeed because generics are erased. So its class cast to a class. But 这篇关于Class.asSubclass签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
正如@egelev所示,我的确可以说我的以另一种方式提问......事实上,返回输入参数原样将毫无意义。所以真正的问题是:
Class.asSubclass方法与普通投射相比,真正有用吗?在发生转换问题时,两者都会抛出一个ClassCastException异常。
AnnotatedElement元素;
...
element.getAnnotation(annotationType.asSubclass(Annotation.class));
< T扩展Annotation> T getAnnotation(Class< T> annotationClass);
public< U>类< U> asSubclass(Class< U> clazz)
我认为我的一般问题已经解决了;非常感谢你。如果有人有关于asSubclass签名的正确性的其他好例子,请将它们添加到讨论中,我希望看到一个使用asSubclass和我的签名的完整示例,显然不起作用。 Class <?扩展U>
。让我们先尝试理解 getClass
签名:
AbstractList< String> ls = new ArrayList<>();
Class <?扩展AbstractList> x = ls.getClass();
类< AbstractList的> x = ls.getClass();
ls.getClass
应该是 ArrayList.class
而不是 AbstractList.class
。由于 ls
ls.getClass
return Class
Class< ArrayList>
,也不能返回 Class< AbstractList>
。但是因为我知道 ls
确实是一个AbstractList,所以实际的类对象只能是AbstractList的一个子类型。所以 Class <?扩展AbstractList>
是一个非常安全的选择。由于通配符:
您不能执行:
AbstractList< String> ls = new ArrayList<>();
Class <?扩展AbstractList> x = ls.getClass();
Class< ArrayList<?>> xx = x;
Class< AbstractList<>>> xxx = x;
public< U>类< U> asSubClass(Class< U> c)
列表< String> ls = new ArrayList<>();
Class <?扩展列表> x = ls.getClass();
Class< AbstractList> aClass = x.asSubclass(AbstractList.class); //大问题
aClass
是 Class< Arraylist>
而不是 Class< AbstractList>
。所以这不应该被允许! 类< ;?
<我在看这个问题时首先想到的是,为什么它没有被宣布为:
public< U延伸T>类< ;?延伸U> asSubClass(Class< U> c)
Class x = List.class.asSubclass(String.class); // pre java5
//如果asSubclass在
之前被声明,这将不会被编译
public static< T,U extends T>类< ;?延伸U> asCubClaz(Class
return t.asSubClass(c);
}
public static< T,U>类< ;?延伸U> asSubClazOriginal(Class
return t.asSubClass(c);
}
asSubClazOriginal(List.class,String.class);
asSubClaz(List.class,String.class); //错误。所以会打破遗留代码
asSubClass
而不是强制转换? - 因为演员是背叛。例如:
列表< String> ls = new ArrayList<>();
Class <?扩展列表> x = ls.getClass();
Class< AbstractList> aClass =(Class< AbstractList>)x;
aClass.equals(ArrayList.class)
会给出false。所以绝对演员是错的。如果您需要类型安全,您可以使用 asSubClaz
以上public <U> Class<? extends U> asSubclass(Class<U> clazz)
public <U> Class<U> asSubclass(Class<U> clazz)
Class<? extends U>
Class<U>
AnnotatedElement element;
...
element.getAnnotation(annotationType.asSubclass(Annotation.class));
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
public <U> Class<U> asSubclass(Class<U> clazz)
Class<? extends U>
. Lets first try understanding, the getClass
signature:AbstractList<String> ls = new ArrayList<>();
Class<? extends AbstractList> x = ls.getClass();
Class<AbstractList> x = ls.getClass();
ls.getClass
would be ArrayList.class
and not AbstractList.class
. Neither can ls.getClass
return Class<ArrayList>
because ls
is of type AbstractList<> and not Arraylist Class<ArrayList>
nor can I return Class<AbstractList>
. But because I know ls
is an AbstractList for sure, so the actual class object can only be a subtype of AbstractList. So Class<? extends AbstractList>
is a very safe bet. Because of wild card:
You 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
aClass
at runtime is Class<Arraylist>
and not Class<AbstractList>
. So this should not be allowed!! Class<? extends AbstractList>
is the best bet.
public <U extends T> Class<? extends U> asSubClass(Class<U> c)
asSubClass
was declared as shown above.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
asSubClass
rather than cast? - Because cast is betrayal. For example:List<String> ls = new ArrayList<>();
Class<? extends List> x = ls.getClass();
Class<AbstractList> aClass = (Class<AbstractList>) x;
aClass.equals(ArrayList.class)
would give false. So definitely cast is wrong. In case you need type safety, you can use asSubClaz
above