java 泛型 - 转换为 List<SomeType> 会发出未经检查的转换警告,而转换为 SomeType 则不会

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18705482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 10:20:40  来源:igfitidea点击:

java generics - cast to List<SomeType> issues unchecked cast warning while cast to SomeType not

javagenericscastingtype-safetycode-design

提问by Mr_and_Mrs_D

Why this :

为什么这个 :

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

does not generate any warnings while this :

在此期间不会生成任何警告:

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

generates Type safety: Unchecked cast from T to List<ScanResult>?

产生Type safety: Unchecked cast from T to List<ScanResult>?

How can I appease the warning ?
As a design is this kind of method declaration a smell ?

我该如何安抚警告?
作为一种设计,这种方法声明是一种气味吗?

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

is an interface method implemented in different classes with different data types - the first line of all implementations is such a cast

是在具有不同数据类型的不同类中实现的接口方法 - 所有实现的第一行都是这样的强制转换

采纳答案by Katona

You get the warning because the cast (List<ScanResult>) datais not safe. Due to type erasure, List<ScanResult>will be Listduring runtime, so there will be no real type check regarding the element type of the list. That is, that cast will succeed even if you get List<String>as a parameter and later you will get a ClassCastExceptionwhen you try to access the list:

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

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

One way to avoid it is making the interface generic:

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

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

And then define the specific type argument at implementations:

然后在实现中定义特定的类型参数:

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) {
    }
}

I don't know if it is suitable for your needs.

我不知道它是否适合您的需求。

回答by Mr_and_Mrs_D

From Angelika Langer's Java Generics FAQs

来自 Angelika Langer 的Java 泛型常见问题解答

We are prepared to cope with ClassCastException s when there is a cast expression in the source code, but we do not expect ClassCastException s when we extract an element from a list of strings. This sort of unexpected ClassCastException is considered a violation of the type-safety principle. In order to draw attention to the potentially unsafe cast the compiler issues an "unchecked" warning when it translates the dubious cast expression.

当源代码中存在强制转换表达式时,我们准备处理 ClassCastException s,但是当我们从字符串列表中提取元素时,我们不期望 ClassCastException s。这种意外的 ClassCastException 被认为违反了类型安全原则。为了引起对潜在不安全转换的注意,编译器在翻译可疑转换表达式时发出“未检查”警告。

So the answer to my first question is that the cast to SomeTypewill fail there and then if the classes are not compatible - while the List<ScanResult> scanRes = (List<ScanResult>) data;which at run time is just List scanRes = (List) data;won't fail if datais anyList implementation - but might result in a CCE in a remote and completely unrelated part of the codebase - hence it will be real difficult to debug - hence the warning.

因此,我的第一个问题的答案是,SomeType如果类不兼容,则强制转换将在那里失败 - 而如果是任何List 实现List<ScanResult> scanRes = (List<ScanResult>) data;,则在运行时List scanRes = (List) data;不会失败- 但可能会导致 CCE代码库中远程且完全不相关的部分 - 因此调试起来非常困难 - 因此发出警告。data

Another way to put it (by @erickson here) :

另一种方式把它(由@erickson这里):

By doing your own cast up front, you're "complying with the warranty terms" of Java generics: if a ClassCastExceptionis raised, it will be associated with a cast in the source code, not an invisible cast inserted by the compiler.

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