当前位置: 首页 > 面试题库 >

在Java中强制转换为泛型类型不会引发ClassCastException吗?

桂智志
2023-03-14
问题内容

我遇到了Java的异常行为,似乎是一个错误。是吗?即使对象不是的实例,K也无法将对象强制转换为通用类型(例如)。这是一个例子:ClassCastException``K

import java.util.*;
public final class Test {
  private static<K,V> void addToMap(Map<K,V> map, Object ... vals) {
    for(int i = 0; i < vals.length; i += 2)
      map.put((K)vals[i], (V)vals[i+1]); //Never throws ClassCastException!
  }
  public static void main(String[] args) {
    Map<String,Integer> m = new HashMap<String,Integer>();
    addToMap(m, "hello", "world"); //No exception
    System.out.println(m.get("hello")); //Prints "world", which is NOT an Integer!!
  }
}

更新 :感谢cletus和Andrzej
Doyle的有用答案。因为我只能接受一个,我接受安杰伊·多伊尔的答案,因为它使我一个解决方案,我觉得是不是
糟糕。我认为这是在单行代码中初始化小型Map的更好方法。

  /**
   * Creates a map with given keys/values.
   * 
   * @param keysVals Must be a list of alternating key, value, key, value, etc.
   * @throws ClassCastException if provided keys/values are not the proper class.
   * @throws IllegalArgumentException if keysVals has odd length (more keys than values).
   */
  public static<K,V> Map<K,V> build(Class<K> keyClass, Class<V> valClass, Object ... keysVals)
  {
    if(keysVals.length % 2 != 0)
      throw new IllegalArgumentException("Number of keys is greater than number of values.");

    Map<K,V> map = new HashMap<K,V>();
    for(int i = 0; i < keysVals.length; i += 2)
      map.put(keyClass.cast(keysVals[i]), valClass.cast(keysVals[i+1]));

    return map;
  }

然后您这样称呼它:

Map<String,Number> m = MapBuilder.build(String.class, Number.class, "L", 11, "W", 17, "H", 0.001);

问题答案:

就像cletus所说的那样,擦除意味着您不能在运行时检查它(并且由于您的转换,您不能在编译时检查它)。

请记住,泛型仅是编译时功能。集合 对象 没有任何通用参数,只有您创建的对该对象的 引用
。这就是为什么如果您需要从原始类型甚至是向下转换集合时会收到很多关于“未检查的强制转换”的警告的Object原因,因为编译器无法验证对象是否具有正确的泛型类型(如对象本身没有通用类型)。

另外,请记住转换的含义-这是一种告诉编译器“我知道您不一定可以检查类型是否匹配,但是请 相信我 ,我知道它们可以。”
当您(不正确地)覆盖类型检查(然后不正确)而导致类型不匹配时,您应该责怪谁?;-)

您的问题似乎出在缺乏异构通用数据结构的周围。我建议您的方法的类型签名应该更像private static<K,V> void addToMap(Map<K,V> map, List<Pair<K, V>> vals),但是我不认为这样做真的可以给您带来任何好处。成对列表基本上是一个映射,因此构造typesafe
vals参数以调用该方法将与直接填充该映射一样多。

如果您 确实确实 希望大致上保持类不变,但是要添加运行时类型安全性,则以下内容可能会给您一些想法:

private static<K,V> void addToMap(Map<K,V> map, Object ... vals, Class<K> keyClass, Class<V> valueClass) {
  for(int i = 0; i < vals.length; i += 2) {
    if (!keyClass.isAssignableFrom(vals[i])) {
      throw new ClassCastException("wrong key type: " + vals[i].getClass());
    }
    if (!valueClass.isAssignableFrom(vals[i+1])) {
      throw new ClassCastException("wrong value type: " + vals[i+1].getClass());
    }

    map.put((K)vals[i], (V)vals[i+1]); //Never throws ClassCastException!
  }
}


 类似资料:
  • 我在这里遇到了一个关于带列表的泛型有界类型的小问题。请帮帮我! 有什么方法可以克服这个问题,或者我可以安全地压制警告吗?

  • 我有一个父类来处理我所有的自定义异常,父母异常。我希望所有的子异常都有一个方法来向异常添加消息。为了做到这一点,我创建了一个泛型方法,在向其添加消息后返回泛型类型的对象。我在父类方法中使用来添加消息,然后返回,但是由于该方法返回泛型类型,所以我将其转换为泛型类型T。这似乎是可行的,但是给出了警告。我的代码如下: 该行给出的警告是。这种方法似乎确实如预期的那样有效,所以我并不担心,但我想更好地理解为

  • 我有一个通用类。它看起来像这样: 显然,conevertdatajsonstring方法仅在字符串类型为T时调用。但有一个警告: 类型安全:未选中从字符串转换为T 有没有一种方法可以在不使用SuppressWarnings的情况下解决此问题: @抑制警告(“未选中”) 方法之前?

  • 有没有一种简单的方法可以做到这一点: 编辑:我写了一份正确答案的工作副本:

  • 问题内容: 我有以下两节课: 和: 当我运行测试时,一切都是笨拙的。如果我将类型参数化更改为: 编译器抱怨,报告: 错误:类型不兼容的整数不能转换为T number = new Integer(11); 其中T是类型变量T扩展了在方法getSomeValue(boolean)中声明的Object 它同样对Double有所抱怨。为什么? 编辑:我犯了一个错误。这实际上是有效的代码。 现在我明白了@S

  • 强制类型转换 隐式类型转换:隐式类型转换又称为自动类型转换,隐式类型转换可分为三种:算术转换、赋值转换和输出转换。 显式类型转换:显式类型转换又称为强制类型转换,指的是使用强制类型转换运算符,将一个变量或表达式转化成所需的类型,这种类型转换可能会造成数据的精度丢失。 数据有不同的类型,不同类型数据之间进行混合运算时必然涉及到类型的转换问题。 转换的方法有两种: 自动转换(隐式转换):遵循一定的规则