java - 在 Java 中,在泛型实例上调用 getClass 时如何避免原始类型?

标签 java generics reflection language-design bounded-wildcard

假设我在 Java 中有这个:

List<String> list = new ArrayList<String>();
list.getClass();

最后一个表达式的类型是Class<? extends List> .我明白为什么,由于删除,它不能是 Class<? extends List<String>> .但是为什么不能是Class<? extends List<?>>呢? ?

如果我想将这个表达式的结果分配给一个以某种方式保持该类实际上是某种类型的信息 List

Class<? extends List> listClass = list.getClass(); // raw type warning
Class<? extends List<?>> listClass = (Class<? extends List<?>>) list.getClass(); // unchecked cast warning

最佳答案

首次引入泛型时,getClass返回 Class<? extends X> , 其中X是调用它的表达式的静态类型。此行为导致不合理的编译问题,如 this Oracle bug 中所报告.这是该错误报告的示例:

The following program fragment fails to compile

void f(List<Integer> li, List<String> ls) {
    if (li.getClass() == ls.getClass())
  ;
}

because the intersection of Class<List<Integer>> and Class<List<String>> is empty.

此问题已通过扩大 getClass 的返回类型得到解决成为现在的样子。来自 the documentation :

The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called.

这解决了上述问题,但最终导致了您的问题指出的问题。没多久,another bug据报道,争论如下:

I think the getClass() typing rule could be changed to Class<? extends wildcard(T)>

The wildcard operation is defined by: if T is parametrized, wildcard(T)=erasure(T)<?> else , wildcard(T)=T

JUSTIFICATION :

  1. This rule introduce a raw type. Raw type must ONLY be used to interact with legacy code.

  2. The new Rule introduce a wildcard. Relationship between parametrized type and wildcard are based on subtyping rules. Relationship between parametrized type and wildcard are based on raw type conversion.

这个错误没有得到解决,直到今天仍然开放,有以下反驳:

The proposal means that getClass() would return a Class<? extends ArrayList<?>> object, which is incompatible with other Class<? extends ArrayList<?>> objects. This is compatible with existing code like:

List<String> l = ...;
Class<? extends List> c = l.getClass();

because the new type of the RHS, Class<? extends List<?>>, is a subtype of Class<? extends List>.

A disadvantage of enriching Class's type argument is that it will break idiomatic use of Class.cast. Today, you can write:

List<Integer> x = ...;
Class<? extends List> cl = x.getClass();  
List<Integer> y = cl.cast(null);

and get a warning at cast(), because of the unchecked conversion from List to List<Integer>. But with the proposal, the analogous code doesn't compile:

List<Integer> x = ...;
Class<? extends List<?>> cl = x.getClass();
List<Integer> y = cl.cast(null);

because List<?> returned by cast() cannot be converted to List<Integer>. The only way to avoid the error is to cast cl.cast(..) up to List and suffer the unchecked conversion warning to List<Integer>. This is effectively what getClass() does already.

Overall, the proposal seems like a good idea, but it has moderate complexity and a fairly small payoff.

(删节并更正了一些拼写错误)

关于java - 在 Java 中,在泛型实例上调用 getClass 时如何避免原始类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18782882/

相关文章:

java - Spring MVC 中 Bean 对象不能为 null

java - Java 中是否有 libxml2.HTMLparser.htmlSAXParseDoc 的等效项?

c# - 通用 C# 方法

c# - 如何编写为模板化基指定类型参数的派生类

java - 从原始 ArrayList 获取值

java - 带有通用参数的比较会发出警告

.NET 反射 - 将数组类型属性值转换为逗号分隔的字符串

c# - 为什么.NET中_MethodInfo接口(interface)不叫IMethodInfo?

Java 反射性能

java - 如果出现问题并且我想重试,使用相同的 Executor 重新排队 Runnable 是否安全或明智?