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


这可能是一个愚蠢的问题,但我刚看到一个问题 如何为泛型类型创建Type变量。共识似乎是你应该有一个虚拟方法返回该类型,然后使用反射来获取它(在这种情况下,他想要 Map<String, String>)。像这样的东西:

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

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

我的问题是,没有多少使用反射,你不能只做以下事情:

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<String> 这显然是不可能的。


2028
2018-06-07 12:34


起源

我正在尝试执行您提出的解决方案允许的内容:从原始类型获取参数化类型,并在编译时提供Type参数列表。你有没有找到另一种方法呢? - user48956


答案:


当然可以,对于大多数应用来说,它可能就足够了。

但是,使用第一种方法,您将获得更精细的对象。比如说你创建了一个对象 type1 使用第一种方法,和 type2 使用第二种方法。然后 type1.equals(type2) 将返回true(因为第一个方法返回一个正确实现equals方法的对象)但是 type2.equals(type1) 将返回false(因为在第二种方法中,您没有覆盖equals方法,并且正在使用来自的实现 Object)。

相同的推理适用于其他(有时是有用的方法),如 toStringhashCode 第二种方法没有提供这些方法的有用实现。


7
2018-06-07 12:45



实际上,equals的type1(sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl)实现似乎将等于的参数转换为ParameterizedType然后使用接口方法来比较类,所以 type1.equals(type2) 虽然相反(type2.equals(type1))会返回虚假;你也可以实现它们,但随后代码变得有点粗糙 - Andrei Fierbinteanu
当然。您可以在方法2中获得与方法1中相同的结果,但它需要更多的工作,正如您已经注意到的那样。 - aioobe


如果你包含谷歌 番石榴 你的项目中的库(你应该;它很棒),使用它 TypeToken 得到一个类型。谷歌的 GSON 库(用于与JSON交互)有类似的 。两者都是这样使用的(得到一个 Type 代表 List<String>

Type t = new TypeToken<List<String>>(){}.getType();

如果您不想依赖任何第三方库,您仍然可以使用匿名类型来获取泛型 具体 用一行代码键入(这种技术不适用于接口,可能比抽象类型的值更麻烦)。得到一个 Type 代表 HashMap<String, String>, 做这个:

Type t = new HashMap<String, String>(){}.getClass().getGenericSuperclass();

我已经证实了这一点 Type 例 .equals() 该 Type 由...创建的实例 GSONTypeToken,虽然没有验证相同 番石榴的版本 TypeToken,目前我无法访问。 (Guava是一个更通用的库,对于各种各样的东西非常方便,你应该可以使用它。)


6
2017-11-02 20:16



这仍然需要在编译时知道List <String>。在OP中,直到编译类型才知道原始类型和参数类型。 - user48956


实际上,我认为执行此操作的最简单方法(==最少代码)将是一个扩展您感兴趣的类型的虚拟接口,然后 getGenericInterfaces()[0] 从它的类(使用 getGenericSuperclass() 如果你对课程感兴趣):

private interface MapStringString extends Map<String, String> {}
private static ParameterizedType mapStringString(){
    return (ParameterizedType) MapStringString.class.getGenericInterfaces()[0];
}

但是,它不能很好地扩展,因为你必须为每个人创建一个新类 ParameterizedType 你想表达。我不明白为什么你的实现不会这样做(除非在某处有缩小的演员),它确实具有吸引人的好处,你可以使它可重用。


2
2018-06-07 12:56



虽然这看起来像我给出的第一个方法一样“hackish”,但它至少提供了更好看的代码,你尝试获取类型(只是调用函数而不是做get类,然后获取方法,然后每次都得到泛型返回类型)你想用它)。 - Andrei Fierbinteanu