Interesting generics-related discrepancy between javac and Eclipse IDE compiler
I have an interesting discrepancy between javac and Eclipse IDE compiler, and can't figure out who's right. So, the code below compiles with javac, however Eclipse tells me that the static initializer's invocation of "exportAll" is wrong, 'cause:
The method exportAll(Iterable< X.Stat< ? extends Number>>) in the type X is not applicable for the arguments (Collection< capture#1-of ? extends X.S开发者_开发百科tat>)
Who's right? javac or Eclipse?
import java.util.Map;
public class X {
interface Stat<T> {
}
public static void exportAll(Iterable<Stat<? extends Number>> vars) {
}
public static Map<Double, ? extends Stat> getPercentiles() {
return null;
}
static {
exportAll(getPercentiles().values());
}
}
You can't compile your example - you are calling a non-static method getPercentiles
from the static initializer, so I'll assume that it is a static method, too.
In any case, your compiler would at least spit out an "unchecked" warning if you compile with -XLint:unchecked
(Stat takes a type parameter!). I assume you would like the following:
public class X {
interface Stat<T> {
}
public static void exportAll(Iterable<? extends Stat<? extends Number>> vars) {
}
public static Map<Double, ? extends Stat<Double>> getPercentiles() {
return null;
}
static {
exportAll(getPercentiles().values());
}
I assume that your percentiles are an arbitrary subclass of Stat<Double>
, therefore I declared them as ? extends Stat<Double>
in the Map. So the values()
call will return a Collection<? extends Stat<Double>>
.
Collection
implements Iterable
, therefore we are safe on that side.But Collection<? extends Stat<Double>>
is not covered by Iterable<Stat<? extends Number>>
, therefore we need to declare the argument as Iterable<? extends Stat<? extends Number>>
.
The beauty (well, except for the syntax) of having exportAll
take Iterable<? extends Stat<? extends Number>>
is that your Map
could contain all sorts of ? extends Stats<N>
where N
is a subclass of Number
.
Your Map<Double, ? extends Stat>.values()
will have a type of Collection<? extends Stat>
. This Stat
is really Stat<?>
. Your Iterable
requires that the Stat
not just be any old Stat<?>
but rather Stat<? extends Number>
. You would have to change your getPercentiles()
to be Map<Double, ? extends Stat<? extends Number>>
.
public static void exportAll(Iterable<Stat<? extends Number>> vars) {
} // ^ this must match
// your values type on the map
public Map<Double, ? extends Stat<? extends Number>> getPercentiles() {
return null;
}
@emboss here's what I would do in those cases whenever I could:
class Main {
static interface Something<E> {
void doSomething();
}
static class ConcreteSomething<E> implements Something<E> {
E data;
ConcreteSomething(E data) {
this.data = data;
}
public void doSomething() {
System.out.println(data);
}
}
public static void main(String[] args) {
List<Something<Number>> list = new LinkedList<Something<Number>>();
list.add(new ConcreteSomething<Number>(Math.PI)); // an autoboxed Double
list.add(new ConcreteSomething<Number>(new Integer(5))); // an Integer
for(Something<Number> s : list) s.doSomething();
}
}
It doesn't compile in javac. (after adding static to getPercentiles)
Get your facts straight; don't waste other people's time.
Kids today, too much ADD.
精彩评论