如何在Java中获取地图的值类型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3687766/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 03:30:37  来源:igfitidea点击:

How to get value type of a map in Java?

javagenerics

提问by naumcho

Possible Duplicate:
Get generic type of java.util.List

可能的重复:
获取 java.util.List 的泛型类型

I have a Map and I want to get the type of T from an instance of that Map. How can I do that?

我有一个 Map,我想从该 Map 的实例中获取 T 的类型。我怎样才能做到这一点?

e.g. I want to do something like:

例如,我想做类似的事情:

Map<String, Double> map = new HashMap<String, Double>();
...
String vtype = map.getValueType().getClass().getName(); //I want to get Double here

Of course there's no such 'getValueType()' function in the API.

当然,API 中没有这样的“getValueType()”函数。

采纳答案by Andy Thomas

You can't get it from the instance, because in Java generics the type parameter is available only at compile time, not at run time.

您无法从实例中获取它,因为在 Java 泛型中,类型参数仅在编译时可用,在运行时不可用。

This is known as type erasure.A more formal definition is provided in the JLS.

这称为类型擦除。JLS 中提供了更正式的定义

回答by Rob Hruska

Ifyour Mapis a declared field, you can do the following:

如果Map是已声明的字段,则可以执行以下操作:

import java.lang.reflect.*;
import java.util.*;

public class Generic {
    private Map<String, Number> map = new HashMap<String, Number>();

    public static void main(String[] args) {
        try {
            ParameterizedType pt = (ParameterizedType)Generic.class.getDeclaredField("map").getGenericType();
            for(Type type : pt.getActualTypeArguments()) {
                System.out.println(type.toString());
            }
        } catch(NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

The above code will print:

上面的代码将打印:

class java.lang.String
class java.lang.Number

However, if you simply have an instance of the Map, e.g. if it were passed to a method, you cannot get the information at that time:

但是,如果您只有一个 的实例Map,例如,如果它被传递给一个方法,那么您将无法获得当时的信息:

public static void getType(Map<String, Number> erased) {
    // cannot get the generic type information directly off the "erased" parameter here
}

You couldgrab the method signature (again, using reflection like my example above) to determine the type of erased, but it doesn't really get you anywhere (see edit below).

可以获取方法签名(再次,像我上面的示例一样使用反射)来确定 的类型erased,但它并没有真正让您到任何地方(请参阅下面的编辑)。

Edit:

编辑:

BalusC's comments below should be noted. You really shouldn't need to do this; youalready declared the Map's type, so you're not getting any more information than you already have. See his answer here.

应该注意下面 BalusC 的评论。你真的不需要这样做;已经声明了 Map 的类型,所以你没有得到比你已经拥有的更多的信息。在这里看到他的回答

回答by StaxMan

Although correct answers have been given, there is one more alternative which has not yet been pointed out. Basically fields and methods are not the only places where generic type information can live: super-class declaration also has this information.

虽然已经给出了正确的答案,但还有一种选择尚未指出。基本上字段和方法不是泛型类型信息可以存在的唯一地方:超类声明也有这些信息。

This means that if your Map is actually a sub-type like:

这意味着,如果您的 Map 实际上是一个子类型,例如:

class MyStringMap extends HashMap<String,String> { }

then it is possible to figure out generic type parameters that were used, by calling 'getGenericSuperclass' (on 'instance.getClass()'), and then accessing actual type parameters assigned. It does get quite involved since one has to traverse type hierarchy to ensure parameters get properly bound to Map (may be aliased etc), but it can be done. And this is the way "super token" is used to pass generic declaration like:

然后可以通过调用“getGenericSuperclass”(在“instance.getClass()”上),然后访问分配的实际类型参数,找出使用的泛型类型参数。它确实很复杂,因为必须遍历类型层次结构以确保参数正确绑定到 Map(可能是别名等),但它可以做到。这就是“超级令牌”用于传递通用声明的方式,例如:

  new TypeToken<Map<String, Double>>() { }

which is used by many Java frameworks (Jersey, Guice, Hymanson and many more)

许多 Java 框架(Jersey、Guice、Hymanson 等等)都使用它

Problem here is that although this does allow determining nominal types of an instance, it only works if there is actual non-generic sub-class of generic type, and I don't know of a way to enforce this requirement (calling code might find it odd that it must create a somewhat bogus Map sub-class just for this purpose).

这里的问题是,虽然这确实允许确定实例的名义类型,但它仅在存在泛型类型的实际非泛型子类时才有效,而且我不知道强制执行此要求的方法(调用代码可能会发现奇怪的是,它必须为此创建一个有点虚假的 Map 子类)。