代码之家  ›  专栏  ›  技术社区  ›  naumcho

如何在Java中获取映射的值类型?[副本]

  •  11
  • naumcho  · 技术社区  · 15 年前

    可能重复:
    Get generic type of java.util.List

    我有一个映射,我想从这个映射的一个实例中得到T的类型。我该怎么做?

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

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

    3 回复  |  直到 8 年前
        1
  •  7
  •   Andy Thomas    15 年前

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

    中提供了更正式的定义 JLS.

        2
  •  15
  •   Community CDub    8 年前

    如果 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();
            }
        }
    }
    

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

    但是,如果您只是拥有 地图 ,例如,如果将其传递给某个方法,则此时无法获取信息:

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

    能够 erased ,但它并没有真正让你去任何地方(见下面的编辑)。

    编辑:

    巴卢斯克的评论如下。你真的不需要这样做; 已经声明了映射的类型,因此您不会得到比现有更多的信息。看看他的 answer here

        3
  •  2
  •   StaxMan    15 年前

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

    class MyStringMap extends HashMap<String,String> { }
    

    然后可以通过调用“getGenericSuperclass”(on)找出所使用的泛型类型参数实例.getClass()'),然后访问指定的实际类型参数。它确实非常复杂,因为必须遍历类型层次结构以确保参数正确地绑定到映射(可能是别名等),但这是可以做到的。这就是“超级令牌”用来传递泛型声明的方式,比如:

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

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

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