This is a contrived example to illustrate the problem. I know there are ways around this that don't generate compiler warnings and you can also disable the warning. I'm wondering if this is possible without any of those tricks.
Given this code:
1 public static void main(String[] args) {
2 Map<String,String> map = null;
3
4 HashMap<String,String> hmap;
5
6 if(map instanceof HashMap)
7 hmap = (HashMap<String,String>)map;
8 else
9 hmap = new HashMap<String,String>(map);
10
11 map = (Map<String,String>)hmap.clone();
12
13 Object o = hmap.clone();
14 if(o instanceof Map<?,?>)
15 map = (Map<String,String>)o;
16 }
The code on both lines 11 and 15 generate the compiler warning:
Unchecked cast from Object to Map<String,String>
Line 11 is a little understandable: Object.clone()
returns an Object
, and there has been no instanceof
check prior to casting. The programmer knows that the clone will be a Map<String,String>
, but the compiler can't prove it.
Line 15 is puzzling to me, though. Usually, checking the type of a variable using instanceof
and then immediately casting it will not generate such a warning. Indeed, replacing the code with non-parameterized classes like this will generate no warnings, on either of these lines of code:
static class A {}
static class B extends A implements Cloneable {
public Object clone() { return null; }
}
public static void main(String[] args) {
A a = null;
B b;
if(a instanceof B)
b = (B)a;
else
b = new B();
a = (A)b.clone();
Object o = b.clone();
if(o instanceof A)
a = (A)o;
}
Back to the original code (with the Map<String,String>
references), even adding this awkward construction to the end of the code generates a similar warning:
map = (Map<String,String>)hmap.getClass().cast(o);
The warning this time is Unchecked cast from capture#11-of ? extends HashMap to Map<String,String>
. Trying to write:
map = HashMap<String,String>.class.cast(o);
Generates a compiler error because it can't figure out that HashMap<String,String>.class
is a static class reference in the same way that e.g. HashMap.class
, so we have to use a reference of the "correct" type to call Class.cast
.
Is this something that Java just can't do?