【问题标题】:Casting to List<SomeType> issues an unchecked cast warning while casting to SomeType does notjava泛型 - 转换为 List<SomeType> 发出未经检查的转换警告,而不转换为 SomeType
【发布时间】:2013-09-09 19:26:49
【问题描述】:

为什么这样:

public <T> List<byte[]> getData(T data) {
    Location loc = (Location) data;
    // ...
}

在此过程中不会产生任何警告:

public <T> List<byte[]> getData(T data) {
    List<ScanResult> scanRes = (List<ScanResult>) data;
    // ...
}

生成Type safety: Unchecked cast from T to List&lt;ScanResult&gt; ?

我怎样才能安抚警告?
作为一种设计,这种方法声明是一种气味吗?

public <T> List<byte[]> getData(T data)

是不同数据类型的不同类中实现的接口方法——所有实现的第一行就是这样一个演员表

【问题讨论】:

  • 请注意,使用泛型方法并不能购买任何东西——它还不如public List&lt;byte[]&gt; getData(Object data)

标签: java generics casting type-safety code-design


【解决方案1】:

您收到警告是因为演员 (List&lt;ScanResult&gt;) data 不安全。由于type erasureList&lt;ScanResult&gt;在运行时将是List,因此不会对列表的元素类型进行真正的类型检查。也就是说,即使您将List&lt;String&gt; 作为参数,该转换也会成功,稍后当您尝试访问列表时,您将获得ClassCastException

ScanResult result = data.get(0); // ClassCastException: String

避免它的一种方法是使接口通用:

public interface DataProvider<T> {
    public List<byte[]> getData(T data);
}

然后在实现时定义具体的类型参数:

public class DataProviderFromLocation implements DataProvider<Location> {
    public List<byte[]> getData(Location data) {
    }
}

public class DataProviderFromScanResultList implements DataProvider<List<ScanResult>> {
    public List<byte[]> getData(List<ScanResult> data) {
    }
}

不知道是否适合你的需求。

【讨论】:

  • 为什么Location loc = (Location) data; 类型安全?如果我打电话给getData("some string"),它不会在Location loc = (Location) "some string"; 中再次使用CCE 失败吗? +1 参数化界面理念
  • @Mr_and_Mrs_D (Location) data 是类型安全的,因为 Location 不是泛型类型,unchecked cast 仅在转换为泛型类型时才会发出警告,因为类型参数由于类型擦除而丢失(并且在你的情况下只有List“仍然”)。
  • @Mr_and_Mrs_D 这样想:在运行时,T 已被擦除为 Object。但是将Object 转换为Location 仍然是经过检查的转换,如果错误会很快失败。相反,投射到T 将被取消选中。
  • @PaulBellora:谢谢你的澄清——我显然不明白“未检查”是什么——见我的回答below
【解决方案2】:

来自 Angelika Langer 的 Java Generics FAQs

当有演员表时,我们准备处理 ClassCastException 源代码中的表达式,但我们不期望 ClassCastException s 当我们从字符串列表中提取一个元素时。这种 意外的 ClassCastException 被视为违反 类型安全原则。为了引起人们对潜在 unsafe cast 编译器在编译时发出“未经检查”的警告 翻译可疑的演员表。

所以我的第一个问题的答案是,SomeType 的转换将在那里失败,然后如果类不兼容 - 而 List&lt;ScanResult&gt; scanRes = (List&lt;ScanResult&gt;) data; 在运行时只是 List scanRes = (List) data; 不会失败,如果 @ 987654326@ 是 any 列表实现 - 但可能会导致代码库的远程且完全不相关的部分出现 CCE - 因此调试起来非常困难 - 因此会发出警告。

另一种说法(@erickson here):

通过预先进行自己的转换,您“遵守了 Java 泛型的保证条款”:如果引发了 ClassCastException,它将与源代码中的转换相关联,而不是插入的不可见转换由编译器。

【讨论】:

    猜你喜欢
    • 2013-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多