开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜