8

If I compile the code below with javac Test.java -Xlint:unchecked, the assignment to the variable c4 produces a warning due to type erasure. The types here are insignificant, just examples.

Why does the object reference g3 lose the type information about the member variable Comparator<String> strCmp? And why does not c1 issue the same warning, as the only difference is that the class is not generic?

import java.util.Comparator;

public class Test {

    NormalClass n = new NormalClass();
    Comparator<String> c1 = n.strCmp;

    GenericClass<Long> g1 = new GenericClass<Long>();
    Comparator<String> c2 = g1.strCmp;

    GenericClass<?> g2 = new GenericClass<Long>();
    Comparator<String> c3 = g2.strCmp;

    GenericClass g3 = new GenericClass<Long>();
    Comparator<String> c4 = g3.strCmp;
}

class NormalClass {
    public Object t;
    public Comparator<String> strCmp;
}

class GenericClass<T> {
    public T t;
    public Comparator<String> strCmp;
}
  • 5
    Because it's declared as a raw type: GenericClass instead of GenericClass. Don't use raw types. Using them tells the compiler: I want to work in legacy mode, where generic types are ignored. – JB Nizet Jun 12 '15 at 12:35
  • This is very interesting. The `javac` compiler actually produces the described warning, whereas Eclipse - on the other hand - does not. – Seelenvirtuose Jun 12 '15 at 12:36
  • 1
    @Seelenvirtuose http://stackoverflow.com/a/4179798/4807777 – Laurentiu L. Jun 12 '15 at 12:37
  • 1
    See also [What is a raw type and why shouldn't we use it?](http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it) – Jesper Jun 12 '15 at 12:38
  • @JBNizet The difference is that the declaration of `Comparator strCmp` does not depend on the parameter type `T`. And: We are in the world of the compiler, not the runtime. – Seelenvirtuose Jun 12 '15 at 12:38
  • @LaurentiuL. I have set them all to warning! I fear that this question is not as easy as it seems. – Seelenvirtuose Jun 12 '15 at 12:40
  • @Seelenvirtuose: once you declare a variable as a raw type, you set the compiler to legacy mode for this variable, and all its generic members, including the ones using unrelated types, become raw. – JB Nizet Jun 12 '15 at 12:42
  • @JBNizet Ok. That seems to be in-spec (I just read the paragraph 4.8 in JLS 7). But obviously, the Eclipse compiler can do somewhat better. But ... no need to continue discussion here. Thank you. – Seelenvirtuose Jun 12 '15 at 12:44
  • This part is not very well designed, IMHO. The *real* fun question is, what if `GenericClass extends NormalClass` and inherits `strCmp`? What's the desired behavior? What's the specified behavior? What's the implemented behavior? It's a mess. – ZhongYu Jun 12 '15 at 13:00

0 Answers0