I've encountered a strange case of a Java program that doesn't compile and I really don't understand why.
The code can be seen below - note that we have an innerclass parameterized by T but it doesn't use the type parameter (it contains just one field that only involves specific types). The only part that fails to compile is this:
TestClass et2 = new TestClass();
for(String s : et2.columns) {
System.out.println("Joy!");
}
Specifically the line with the "for" loop. The error message is: "error: incompatible types: Object cannot be converted to String". But the strange thing his - no one is asking the compiler to convert an Object to String. I am referring to the "columns" field which is a specific type (ArrayList) so it should be able to iterate over that. That the type parameter of TestClass isn't specified shouldn't cause concern since the compiler doesn't need to know the type parameter, the field has a specific type. As can be seen from the first section, when specifying the type parameter it works. The third section shows that it the compiler could have made it work since a simple move of the value of the columns field into a local variable, and then looping over that, resolves it. But it really shouldn't make a difference. What gives?!
import java.util.ArrayList;
import java.util.List;
public class Tester {
static class TestClass<T>
{
public List<String> columns = new ArrayList<String>();
}
public static void main(String[] args)
{
// When parameterized with Integer it works
TestClass<Integer> et = new TestClass<Integer>();
for(String s : et.columns) {
System.out.println("Joy!");
}
// Doesn't work when not parameterized
TestClass et2 = new TestClass();
for(String s : et2.columns) {
System.out.println("Joy!");
}
// It's OK if we just manually take out the columns field
List<String> columns = et2.columns;
for(String s : columns) {
System.out.println("Joy!");
}
}
}
Someone pointed to What is a raw type and why shouldn't we use it? but I don't think it's exactly relevant. Obviously that would be relevant if the loop was over an array parameterized by because clearly the compiler could only then think of the ArrayList as being essentially ArrayList. But in this case the array doesn't depend on T, it's going to be a String no matter how the class is parameterized.