java generics - cast to List issues unchecked cast warning while cast to SomeType not
java generics - cast to List<SomeType> issues unchecked cast warning while cast to SomeType not
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
public List<byte> getData(Object data)
2 Answers
2
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.
And why is
Location loc = (Location) data;
type safe ? If I call getData("some string")
wont it fail in Location loc = (Location) "some string";
again with CCE ? +1 for the parametrized interface idea– Mr_and_Mrs_D
Sep 9 '13 at 20:09
Location loc = (Location) data;
getData("some string")
Location loc = (Location) "some string";
@Mr_and_Mrs_D
(Location) data
is type safe since Location
is not generic type, unchecked cast
warning is emitted only when casting to a generic type since the type argument is lost due to type erasure (and only List
"remains" in your case).– Katona
Sep 9 '13 at 20:17
(Location) data
Location
unchecked cast
List
@Mr_and_Mrs_D Think of it this way: at runtime,
T
has been erased to Object
. But casting an Object
to Location
is still a checked cast, and will fail fast if wrong. Casting to T
would be unchecked, in contrast.– Paul Bellora
Sep 10 '13 at 3:44
T
Object
Object
Location
T
@PaulBellora: thanks that clarifies it - I apparently did not grok what "Unchecked" was about - see my answer below
– Mr_and_Mrs_D
Sep 11 '13 at 18:02
From Angelika Langer's Java Generics FAQs
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.
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 any List 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<ScanResult> scanRes = (List<ScanResult>) data;
List scanRes = (List) data;
data
Another way to put it (by @erickson here) :
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
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Note that having the method generic doesn't buy anything - it might as well be
public List<byte> getData(Object data)
.– Paul Bellora
Sep 10 '13 at 3:46