使用匿名类创建参数化类型对象
这可能是一个愚蠢的问题,但我刚刚看到一个问题,询问如何为generics类型创建一个Type变量 。 共识似乎是你应该有一个返回该类型的虚方法,然后使用reflection来获取它(在这种情况下,他想要Map
)。 像这样的东西:
public Map dummy() { throw new Error(); } Type mapStringString = Class.forName("ThisClass").getMethod("dummy").getGenericReturnType();
我的问题是,没有多少使用reflection,你不能只做以下事情:
Type mapStringString = new ParameterizedType() { public Type getRawType() { return Map.class; } public Type getOwnerType() { return null; } public Type[] getActualTypeArguments() { return new Type[] { String.class, String.class }; } };
这会有用吗? 如果没有,为什么不呢? 如果它有什么危险/问题(除了能够返回一些类似Integer
类型,这显然是不可能的)。
当然可以,对于大多数应用来说,它可能就足够了。
但是,使用第一种方法,您将获得更精细的对象。 例如,假设您使用第一种方法创建对象type1
,使用第二种方法创建type2
。 然后type1.equals(type2)
将返回true(因为第一个方法返回一个正确实现equals方法的对象)但是type2.equals(type1)
将返回false(因为在第二个方法中,你没有重写equals -method,并且正在使用Object
的实现)。
相同的推理适用于其他(有时是有用的方法),如toString
, hashCode
等。第二种方法不提供这些的有用实现。
如果您在项目中包含Google的Guava库(您应该;它很棒),请使用其TypeToken
来获取类型。 Google的Gson库(用于与JSON交互)具有类似的版本 。 两者都像这样使用(获取表示List
的Type
:
Type t = new TypeToken>(){}.getType();
如果你不想依赖任何第三方库,你仍然可以使用匿名类型来获得具有一行代码的通用具体类型(这种技术不适用于接口,并且可能比它的摘要更麻烦类型)。 要获取表示HashMap
的Type
,请执行以下操作:
Type t = new HashMap(){}.getClass().getGenericSuperclass();
我已经validation了生成的Type
实例.equals()
是由Gson的TypeToken
创建的Type
实例,但是对于Guava的TypeToken
版本没有validation相同,我目前无法访问它。 (Guava是一个更通用的库,对于各种各样的东西非常方便,你应该可以使用它。)
实际上,我认为执行此操作的最简单方法(==最少代码)将是扩展您感兴趣的类型的虚拟接口,然后从其类中获取getGenericInterfaces()[0]
getGenericSuperclass()
如果您感兴趣,请使用getGenericSuperclass()
一类):
private interface MapStringString extends Map {} private static ParameterizedType mapStringString(){ return (ParameterizedType) MapStringString.class.getGenericInterfaces()[0]; }
但是,它不能很好地扩展,因为您必须为要表示的每个ParameterizedType
创建一个新类。 我不明白为什么你的实现不会这样做(除非在某处有缩小的演员),它确实具有吸引人的好处,你可以使它可重用。