FULL PRODUCT VERSION :
[cps@loddont genericsTest]$ java -version
java version "1.5.0_13"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_13-b05)
Java HotSpot(TM) Server VM (build 1.5.0_13-b05, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux loddont 2.6.22.9-61.fc6PAE #1 SMP Thu Sep 27 18:27:50 EDT 2007 i686 i686 i386 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
This appears to occur when you define a class inside a method and there are generic types in the outer class. It appears that they do not pass to the nested class (sorry if thats the wrong terminology for a named class in a method). I believe this is a bug because it used to compile and it seems inconsistent. You can minimally reproduce this by trying to compile this lot:-
public interface Foo<T> {
T foo();
}
public class Bar<T> implements Foo<T> {
public T foo() {
class FooImpl implements Foo<T> {
public T foo() {
return null;
}
}
return new FooImpl().foo();
}
}
You get this error with javac/1.6.0_4
[cps@loddont genericsTest]$ /usr/java/jdk1.6.0_04/bin/javac -d classes src/*
src/Bar.java:9: incompatible types
found : java.lang.Object
required: T
return new FooImpl().foo();
^
1 error
However, as indicated, java 1.5.0 is quite happy:-
[cps@loddont genericsTest]$ /usr/java/jdk1.5.0/bin/javac -d classes src/*
[cps@loddont genericsTest]$
It seems unlikely that this is the correct behaviour since if the type T is not available in the nested class, then I'd exect the line
class FooImpl implements Foo<T> {
to fail to compile because T isn't defined.
I should mention that the eclipse compiler is quite happy with this construct. Maybe they're wrong but I would still suggest that the javac compiler doesn't make much sense here as the generic type T is clearly visible in some sense.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Create src dir and classes dir.
2) Put 'foo.java' and 'bar.java' in src dir.
3) javac -d classes src/*
REPRODUCIBILITY :
This bug can be reproduced always.
CUSTOMER SUBMITTED WORKAROUND :
The following modified version of Bar does compile with 1.6.0_4 and 1.5.0 oddly enough
public class Bar<T> implements Foo<T> {
public T foo() {
class FooImpl<T2 extends T> implements Foo<T> {
public T foo() {
return null;
}
}
return new FooImpl<T>().foo();
}
}
as does the slightly more sensible version
public class Bar<T> implements Foo<T> {
public T foo() {
class FooImpl<T2> implements Foo<T2> {
public T2 foo() {
return null;
}
}
return new FooImpl<T>().foo();
}
}
So you can always make the class external and/or add parameterised types. I was only doing this because the class concerned was never likely to be of use outside the method so it seemed the best place for it.