【问题标题】:Generic 0 cannot be cast to java.lang.ShortGeneric 0 不能转换为 java.lang.Short
【发布时间】:2013-03-04 10:26:06
【问题描述】:

我的班级有两张地图(我是泛型新手)

private Map<Integer, Integer> aMap = new ConcurrentHashMap<Integer, Integer>();
private Map<Integer, Short> bMap = new HashMap<Integer, Short>();

如果地图中不存在键,我想获得零值。所以我做了这个包装方法来最小化输入containsKey(key)

@SuppressWarnings("unchecked")
private <T extends Number> T getValue (Map<Integer, T> map, Integer key) {
    return (T) ((map.containsKey(key)) ? map.get(key) : 0);
}

我这样称呼它

Integer a = getValue(aMap, 15); //okay in any case
Short b = getValue(bMap, 15); //15 key does not exist

对于第二种情况,它给了我:

ClassCastException: java.lang.Integer cannot be cast to java.lang.Short

所以我可能需要做类似: new Number(0) 的事情,但数字是抽象的。

我该如何解决?

编辑:

我的想法是在没有额外 if 的情况下进行算术运算:

Integer a = getValue(aMap, 15);
a = a + 10;

【问题讨论】:

  • 如果您返回 null 而不是零,则不会出现此问题。无论如何它可能更正确,因为零实际上是一个有效值(除非您说您的地图将永远包含这些)。

标签: java generics map casting bounded-wildcard


【解决方案1】:

一种方法是将默认值作为参数提供给您的函数:

private <T extends Number> T getValue (Map<Integer, T> map, Integer key, T dflt) {
    return (T) ((map.containsKey(key)) ? map.get(key) : dflt);
}

public static void main(String[] args) {
    Integer a = getValue(aMap, 15, 0); //okay in any case
    Short b = getValue(bMap, 15, (short)0); //15 key does not exist
}

【讨论】:

    【解决方案2】:

    好吧,如果不以代码可以查看的方式提供T,您将无能为力。

    此时最简单的方法可能是保留一个 0 值的地图:

    private static Map<Class<?>, Number> ZERO_VALUES = createZeroValues();
    
    private static Map<Class<?>, Number> createZeroValues() {
        Map<Class<?>, Number> ret = new HashMap<Class<?>, Number>();
        ret.put(Integer.class, (int) 0);
        ret.put(Short.class, (short) 0);
        ret.put(Long.class, (long) 0);
        // etc
    }
    

    然后:

    private <T extends Number> T getValue (Map<Integer, T> map, Integer key, Class<T> clazz) {
        return clazz.cast(map.containsKey(key) ? map.get(key) : ZERO_VALUES.get(clazz));
    }
    

    那么不幸的是,您不得不将其称为:

    Short b = getValue(bMap, 15, Short.class);
    

    基本上这是Java泛型的一个限制:(

    【讨论】:

    • 感谢您的快速回答!但 NPE 的解决方案似乎更简单。
    【解决方案3】:

    在这种情况下,我只是重写get() 方法:

     private Map<Integer, Short> bMap = new HashMap<Integer, Short>() {
         @Override
         public Short get(Object key) {
             return containsKey(key) ? super.get(key) : new Short(0);
         }
     };
    

    然后你可以在任何地方使用它,它会按照你指定的方式运行。

    【讨论】:

    • Thx :) 我经常使用这种技术。顺便说一句,您可以“不接受”答案,并接受其他人:)
    • 顺便说一句,为什么是super.get(key)?不应该只是get.key();吗?
    • 调用get(key) 将是递归的——该方法将调用自身(因为您正在覆盖 get 方法)。调用super.get(key) 调用HashMap 的实现。请记住,匿名类是编码类的子类
    • “记住匿名类是编码类的子类。”我错过了,谢谢!
    【解决方案4】:

    将 0 显式转换为 short,因为它默认为 int。然后转换为 Short wrapper。在 java 中,你不能直接从原始类型转换为不同类型的 Wrapper。

    【讨论】:

    • 如果您正在考虑在 getValue 方法中编写 (short) 0,这将适用于 short 和 int,但不适用于例如双打。
    • 那么正如之前的帖子中所说,您将必须在地图中具有不同的值。否则返回null。因为不可能进行隐式转换
    • 鉴于 OP 的要求,听起来它不需要为双打工作?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 2019-04-10
    • 1970-01-01
    • 2013-01-22
    • 2011-10-06
    相关资源
    最近更新 更多