简体   繁体   English

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

[英]Creating parameterized type object using anonymous class

This might be a stupid question, but I just saw a question asking how to create a Type variable for a generic type .这可能是一个愚蠢的问题,但我刚刚看到一个问题,询问如何为泛型 type 创建一个 Type 变量 The consensus seemed to be that you should have a dummy method returning that type, and then use reflection to get it (in this case he wanted Map<String, String> ).共识似乎是你应该有一个返回该类型的虚拟方法,然后使用反射来获取它(在这种情况下他想要Map<String, String> )。 Something like this :像这样的事情:

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

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

My question is, not having used reflection that much, couldn't you just do something like:我的问题是,没有那么多使用反射,你不能做这样的事情:

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 };
    }
};

Would this work?这行得通吗? If not, why not?如果没有,为什么不呢? And what are some of the dangers/problems if it does (besides being able to return some Type like Integer<String> which is obviously not possible.如果确实如此,会有哪些危险/问题(除了能够返回某些类型,如Integer<String>这显然是不可能的。

Sure you could, and for most applications it would probably be sufficient.当然可以,而且对于大多数应用程序来说,这可能就足够了。

However, using the first method, you get a more refined object.但是,使用第一种方法,您可以获得更精致的对象。 Let's say for instance that you create an object type1 using the first method, and type2 using the second method.例如,假设您使用第一种方法创建对象type1 ,使用第二种方法创建对象type2 Then type1.equals(type2) would return true (since the first method returns an object that properly implements the equals-method) but type2.equals(type1) would return false (since in the second method, you haven't overridden the equals-method, and are using the implementation from Object ).然后type1.equals(type2)将返回 true(因为第一个方法返回一个正确实现 equals 方法的对象)但type2.equals(type1)将返回 false(因为在第二个方法中,您没有覆盖 equals -method,并且正在使用Object的实现)。

Same reasoning applies to other (sometimes useful methods) such as toString , hashCode etc. The second method does not provide useful implementations of these.同样的推理适用于其他(有时有用的方法),例如toStringhashCode等。第二种方法不提供这些的有用实现。

If you include Google's Guava library in your project (you should; it's great), use its TypeToken to get a type.如果您的项目中包含 Google 的Guava库(您应该这样做;它很棒),请使用它的TypeToken来获取类型。 Google's Gson library (for interacting with JSON) has a similar version . Google 的Gson库(用于与 JSON 交互)有一个类似的版本 Both are used like this (to get a Type representing List<String> :两者都像这样使用(获取表示List<String>Type

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

If you don't want to rely on any third-party libraries, you can still use anonymous types to get a generic concrete type with one line of code (this technique will not work with interfaces and could be more trouble than it's worth for Abstract Types).如果您不想依赖任何第三方库,您仍然可以使用匿名类型通过一行代码获得通用的具体类型(这种技术不适用于接口,并且可能比 Abstract 的价值更麻烦类型)。 To get a Type representing HashMap<String, String> , do this:要获取表示HashMap<String, String>Type ,请执行以下操作:

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

I have verified that resulting Type instance .equals() the Type instances created by Gson 's TypeToken , though have not verified the same for Guava 's version of TypeToken , which I do not have access to at the moment.我已经验证生成的Type实例.equals()是由GsonTypeToken创建的Type实例,但尚未验证Guava版本的TypeToken ,我目前无法访问。 (Guava is a more general-purpose library that is so handy for all sorts of things, you should probably be using it anyways.) (Guava 是一个更通用的库,它对各种事情都非常方便,无论如何你都应该使用它。)

Actually, I think the simplest way (== least code) to do this would be a dummy interface extending the type your interested in, and then getGenericInterfaces()[0] from its class (use getGenericSuperclass() if you're interested in a class):实际上,我认为最简单的方法(==最少代码)是一个扩展您感兴趣的类型的虚拟接口,然后从它的类中获取getGenericInterfaces()[0] getGenericSuperclass()如果您感兴趣,请使用getGenericSuperclass()一类):

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

It doen't scale well, though, as you have to create a new class for every ParameterizedType you want to represent.但是,它不能很好地扩展,因为您必须为要表示的每个ParameterizedType创建一个新类。 I don't see why your implementation wouldn't do (unless there are narrowing casts somewhere), and it does have the appealing benefit that you can make it reusable.我不明白为什么你的实现不会做(除非在某处有缩小强制转换),而且它确实有一个吸引人的好处,你可以使它可重用。

In addition to the mentioned libs from Google there is also a lib from Apache that does the job.除了上面提到的来自 Google 的库之外,还有一个来自 Apache 的库可以完成这项工作。

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

Finde code on GitHub here and Maven artifacts here .在GitHub上FINDE代码在这里和Maven的文物在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM