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

nau*_*cho 12 java generics

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

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

例如,我想做的事情如下:

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

当然,API中没有这样的'getValueType()'函数.

Rob*_*ska 14

如果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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码将打印:

class java.lang.String
class java.lang.Number
Run Code Online (Sandbox Code Playgroud)

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

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

可以获取方法签名(再次使用反射,如上面的示例)来确定类型erased,但它并没有真正让你到任何地方(见下面的编辑).

编辑:

应该注意下面的BalusC的评论.你真的不应该这样做; 已经宣布了Map的类型,所以你没有得到比现有更多的信息.在这里看到他的答案.

  • 注意到应该只返回**声明的**泛型类型(如`Map <String,Integer> map`部分),而不是**实例化的**泛型类型(如`new HashMap <String,Integer> ()`部分).正如我在链接副本中的答案所指出的那样; 如果您已经在代码中自己声明了它们,那就没有必要用这种方式来判断它们...... (4认同)

And*_*mas 7

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

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

  • 这不准确; 有答案给出了完成它所需的确切代码,有两种不同的方式 (2认同)
  • 实际上,对于这种特殊情况,这是100%正确的:如果您所拥有的只是实例,则没有要查找的类型信息,什么都没有.有问题的地图是HashMap类型,因为这里的类型参数在编译后被丢弃(它们在字节代码中引入必要的类型转换). (2认同)