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
java generics - cast to List<SomeType> issues unchecked cast warning while cast to SomeType not
提问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>) data
is not safe. Due to type erasure, List<ScanResult>
will be List
during 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 ClassCastException
when 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 SomeType
will 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 data
is 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
ClassCastException
is raised, it will be associated with a cast in the source code, not an invisible cast inserted by the compiler.
通过
ClassCastException
预先进行自己的转换,您“遵守了 Java 泛型的保证条款”:如果 a被引发,它将与源代码中的转换相关联,而不是编译器插入的不可见转换。