I got a strange compiler error when using generics within a for-each loop in Java. Is this a Java compiler bug, or am I really missing something here?
Here is my whole class:
public class Generics<T extends Object> {
public Generics(T myObject){
// I didn't really need myObject
}
public List<String> getList(){
List<String> list = new ArrayList<String>();
list.add("w00t StackOverflow");
return list;
}
public static void main(String...a){
Generics generics = new Generics(new Object());
for(String s : generics.getList()){
System.out.println(s);
}
}
}
The compiler is complaining about the line with the for-each: "Type mismatch cannot convert from element type Object to String."
If I make this subtle change, it compiles:
public static void main(String...a){
Generics<?> generics = new Generics(new Object());
for(String s : generics.getList()){
System.out.println(s);
}
}
I know getList()
does use generics, but it uses them in what I thought was a completely unrelated way. I could understand this if I were trying to iterate over something of type T and getList()
returned a List<T>
or something, but that's not the case here. The return type of getList()
should have absolutely nothing to do with T and shouldn't care whether I use the raw type for my Generics object or not...right? Shouldn't these be completely unrelated, or am I really missing something here?
Note that the code also compiles if I do this, which I thought should have been equivalent to the first as well:
public static void main(String...a){
Generics generics = new Generics(new Object());
List<String> list = generics.getList();
for(String s : list){
System.out.println(s);
}
}
The difference is that when you use the raw type, all the generic references within the member signatures are converted to their raw forms too. So effectively you're calling a method which now has a signature like this:
List getList()
Now as for why your final version compiles - although it does, there's a warning if you use -Xlint
:
Generics.java:16: warning: [unchecked] unchecked conversion
List<String> list = generics.getList();
^
This is similar to:
List list = new ArrayList();
List<String> strings = list;
... which also compiles, but with a warning under -Xlint
.
The moral of the story: don't use raw types!
Change the line
Generics generics = new Generics(new Object());
to
Generics<?> generics = new Generics<Object>(new Object());
The root of your problem is that you are using a raw type so the type of the getList
method is List
, not List<String>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With