【问题标题】:Type safety : Unchecked cast and Generics类型安全:未经检查的强制转换和泛型
【发布时间】:2011-03-10 04:32:29
【问题描述】:

我有一张非常简单的地图

private Map<String,T> map = Collections.synchronizedSortedMap(new TreeMap<String,T>());

我想定义如下方法

public T[] values(){
    return (T[])map.values().toArray();
}

显然,我最终遇到了未经检查的演员表问题...我的问题是我无法调用 toArray(new T[size])

我应该怎么做才能避免这个警告(不使用@SuppressedWarning)

谢谢

【问题讨论】:

  • 为什么不能调用 toArray(new T[size])??.
  • 在 Java 中你不能创建一个通用的 T 数组 => 你的代码不会编译
  • 这将使调用代码在运行时崩溃,因为 toArray() 本身返回一个 Object[] 数组,而泛型转换是一个 noop。

标签: java generics map casting type-safety


【解决方案1】:

避免使用数组。返回List&lt;T&gt;

数组是必要的基本构建块,但是它们在类型系统中非常奇怪。最好在 API 中避免使用它们。几乎任何地方都可以用 ArrayList 替换数组。性能相同。

【讨论】:

  • 是的,数组就像字符串。有时它们被视为基元,有时它们被视为集合。最好使用真正的收藏。
【解决方案2】:

我应该怎么做才能避免这个警告 (不使用@SuppressedWarning)

此警告是您最不应该担心的事情。更大的问题是,当它返回给期望具有特定类的数组的人时,它会因ClassCastException 而崩溃。

因为 Java 中的数组在运行时包含对其组件类的引用,所以在不知道类的情况下不可能构造这样的数组。要么让用户传入一些东西,你才能获得类T的类对象,或者你只需​​要返回一个Object[]

【讨论】:

    【解决方案3】:

    我能想到的最好的事情是为你的类创建一个构造函数,它接受一个类型为 T 的数组(即一个 T[] 参数)。您的班级的用户应该提供一个大小为零的数组。然后,您可以使用此数组进行 toArray(T[]) 调用。

    【讨论】:

    • 我找不到让用户在构造函数中提供 T.class 对象的方法,因为似乎没有办法从类实例构造一个零大小的数组而不遇到相同的未经检查的强制转换异常。
    • 您可以通过Array.newInstance() 使用反射构造一个数组。当然,它仍然会有警告;但它不会因类转换异常而崩溃。
    【解决方案4】:

    要获得一个泛型类型的数组,您必须将一个 Class 对象传递给您的方法,否则它将返回一个 Object[] 类型的数组。

    public T[] values(Class<T> cl){
        return (T[])map.values().toArray((T[])Array.newInstance(cl,0));
    }
    

    您仍然需要对此代码使用 SuppressdWarning,但它不会在运行时抛出。此外,如果您需要它来实现 collection.values() 您必须在您的 ctor 中传递该类。数组和泛型不能很好地混合,这就是为什么你应该更喜欢使用集合。

    【讨论】:

      猜你喜欢
      • 2015-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多