Java 使用匿名类创建参数化类型对象

Java 使用匿名类创建参数化类型对象,java,generics,Java,Generics,这可能是个愚蠢的问题,但我刚才看到一个问题在问。大家的共识似乎是,应该有一个伪方法返回该类型,然后使用反射来获取它(在本例中,他希望Map)。大概是这样的: public Map<String, String> dummy() { throw new Error(); } Type mapStringString = Class.forName("ThisClass").getMethod("dummy").getGenericReturnType(); 这样行吗?若否,原因为何

这可能是个愚蠢的问题,但我刚才看到一个问题在问。大家的共识似乎是,应该有一个伪方法返回该类型,然后使用反射来获取它(在本例中,他希望
Map
)。大概是这样的:

public Map<String, String> dummy() { throw new Error(); }

Type mapStringString = Class.forName("ThisClass").getMethod("dummy").getGenericReturnType();

这样行吗?若否,原因为何?如果它这样做,会有哪些危险/问题(除了能够返回一些类型,如
Integer
,这显然是不可能的。

当然可以,对于大多数应用程序来说,这可能就足够了

但是,使用第一种方法,您会得到一个更精细的对象。例如,您使用第一种方法创建一个对象
type1
,使用第二种方法创建一个对象
type2
。然后
type1.equals(type2)
将返回true(因为第一种方法返回一个正确实现equals方法的对象)但是
type2.equals(type1)
将返回false(因为在第二个方法中,您没有重写equals方法,并且正在使用
对象的实现)


同样的推理也适用于其他方法(有时是有用的方法),例如
toString
hashCode
等。第二种方法没有提供这些方法的有用实现。

实际上,我认为最简单的方法(=最少的代码)是使用一个虚拟接口来扩展您感兴趣的类型,然后从它的类扩展它(如果您对课程感兴趣,请使用):

private接口MapStringString扩展了映射{}
私有静态参数化类型mapStringString(){
返回(ParameterizedType)MapStringString.class.getGenericInterfaces()[0];
}
不过,它的伸缩性不好,因为您必须为要表示的每个
参数化类型创建一个新类。我不明白您的实现为什么做不到(除非在某个地方有缩小强制类型转换),并且它确实有一个吸引人的好处,那就是你可以使它可重用。

如果你的项目中包括谷歌的库(你应该;它很棒),那么使用它来获取一个类型。谷歌的库(用于与JSON交互)有一个类似的功能。两者都是这样使用的(获取一个表示<代码>列表的<代码>类型)


我已经验证了生成的
Type
instance
.equals()
由创建的
Type
实例,但尚未验证的版本与的相同,我目前无法访问该版本。(Guava是一个更通用的库,它对各种事情都非常方便,你可能无论如何都应该使用它。)

除了上面提到的Google的lib之外,还有一个Apache的lib来完成这项工作

import org.apache.commons.lang3.reflect.TypeUtils;
...
ParameterizedType type = TypeUtils.parameterize(List.class, Double.class);
...

在GitHub和Maven工件上查找代码。

实际上,equals的type1(sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl)实现似乎将equals的参数强制转换为ParameterizedType,然后使用接口方法比较类,因此
type1.equals(type2)
将返回true,尽管相反(
type2.equals(type1)
)将返回false;您也可以实现这些,但代码会有一点chunkySure。您可以在方法2中获得与方法1相同的结果,但正如您所注意到的,它需要更多的工作。虽然这与我给出的第一个方法一样“黑客”,但至少在您尝试获取类型的地方,它会提供外观更好的代码(每次使用时,只需调用函数,而不是执行get类、get方法和get泛型返回类型)。这仍然要求列表在编译时是已知的。在OP中,原始类型和参数类型直到编译时才知道。我正在尝试执行您建议的解决方案所允许的操作:从编译时提供的原始类型和类型参数列表中获取参数化类型。您找到其他方法了吗?
private interface MapStringString extends Map<String, String> {}
private static ParameterizedType mapStringString(){
    return (ParameterizedType) MapStringString.class.getGenericInterfaces()[0];
}
Type t = new TypeToken<List<String>>(){}.getType();
Type t = new HashMap<String, String>(){}.getClass().getGenericSuperclass();
import org.apache.commons.lang3.reflect.TypeUtils;
...
ParameterizedType type = TypeUtils.parameterize(List.class, Double.class);
...