oracle JDK中ParameterizedType
接口的实现类sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
的toString
方法有一个bug。
就是对于内置泛型类toString方法显示的内容不正确:
下面的代码,返回java.util.Map.entrySet()
方法的返回类型:
Type returnType = java.util.Map.class.getMethod("entrySet").getGenericReturnType();
System.out.println(returnType);
我们知道entrySet()
方法的返回类型应该是Set<Map.Entry<K, V>>
,但上面的代码的执行结果却是
java.util.Set<java.util.Map.java.util.Map$Entry<K, V>>
这是个老问题了,java官网上也有这个bug报告:
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6376382
然并卵,jdk 1.7直到1.8都存在这个bug(我没有装1.9,不知道是否解决)
如果你查看ParameterizedTypeImpl的源码会发现这个问题非常好解决,就是程序员笔误,该用Class.getSimpleName()
错误的用了Class.getName()
方法,导致,参见下面toString()
方法的注释:
public String toString() {
StringBuilder sb = new StringBuilder();
if (ownerType != null) {
if (ownerType instanceof Class)
sb.append(((Class)ownerType).getName());
else
sb.append(ownerType.toString());
sb.append(".");
if (ownerType instanceof ParameterizedTypeImpl) {
// Find simple name of nested type by removing the
// shared prefix with owner.
sb.append(rawType.getName().replace( ((ParameterizedTypeImpl)ownerType).rawType.getName() + "$",
""));
} else
// 这里应该用getSimpleName
sb.append(rawType.getName());
} else
sb.append(rawType.getName());
if (actualTypeArguments != null &&
actualTypeArguments.length > 0) {
sb.append("<");
boolean first = true;
for(Type t: actualTypeArguments) {
if (!first)
sb.append(", ");
if (t instanceof Class)
sb.append(((Class)t).getName());
else
sb.append(t.toString());
first = false;
}
sb.append(">");
}
return sb.toString();
}
这是个非常小的Bug,如果你的项目中不关注也就过去了。但如果想改它,就得自己写个ParameterizedType
的实现才行,
为此我写了个ParameterizedTypeImpl.java用于解决这个小bug,完整代码参见gitee仓库:
ParameterizedTypeImpl.java
测试代码参见:
ParameterizedTypeTest.java