【问题标题】:Interesting generics-related discrepancy between javac and Eclipse IDE compilerjavac 和 Eclipse IDE 编译器之间有趣的泛型相关差异
【发布时间】:2011-09-01 00:24:55
【问题描述】:

我在 javac 和 Eclipse IDE 编译器之间有一个有趣的差异,我不知道谁是对的。因此,下面的代码使用 javac 编译,但是 Eclipse 告诉我静态初始化程序对“exportAll”的调用是错误的,因为:

类型 X 中的方法 exportAll(Iterable>) 不适用于参数 (Collection)

谁是对的? javac 还是 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());
}

}

【问题讨论】:

  • getPercentiles 也应该是静态的,不是吗?否则它不会在任何一个上编译;)
  • 尽管有这个示例,但 eclipse java 编译器中存在错误,它完全拒绝 sun java 编译器接受的泛型构造。最近我遇到了相反的情况,eclipse 3.7 接受了 sun 的 6u21 拒绝的推断。

标签: java eclipse generics


【解决方案1】:

您无法编译您的示例 - 您正在从静态初始化程序调用非静态方法 getPercentiles,因此我假设它也是静态方法。

在任何情况下,如果您使用-XLint:unchecked 进行编译,您的编译器至少会发出“未经检查”的警告(Stat 采用类型参数!)。我假设您想要以下内容:

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());
}

我假设您的百分位数是Stat&lt;Double&gt; 的任意子类,因此我在地图中将它们声明为? extends Stat&lt;Double&gt;。所以values() 调用将返回Collection&lt;? extends Stat&lt;Double&gt;&gt;

Collection 实现了Iterable,因此我们在那边是安全的。但是Collection&lt;? extends Stat&lt;Double&gt;&gt; 不被Iterable&lt;Stat&lt;? extends Number&gt;&gt; 覆盖,因此我们需要将参数声明为Iterable&lt;? extends Stat&lt;? extends Number&gt;&gt;

exportAll 使用Iterable&lt;? extends Stat&lt;? extends Number&gt;&gt; 的美妙之处(当然,除了语法之外)是您的Map 可以包含各种? extends Stats&lt;N&gt;,其中NNumber 的子类。

【讨论】:

  • 谢谢。现在,这实际上不是我编写的代码,我只是想使用它——我的用法是“exportAll(getPercentiles().values())”行。我可以找到修改它的方法;确实与您提出的解决方案相同。然而,我的问题是为什么它用 javac 编译而不是用 Eclipse 编译。正如@irreputable 正确注意到的那样,这个小示例也不能使用 javac 编译,这很令人费解,因为它编译了我从中提取示例的较大源代码体。
【解决方案2】:

您的Map&lt;Double, ? extends Stat&gt;.values() 将具有Collection&lt;? extends Stat&gt; 的类型。这个Stat 真的是Stat&lt;?&gt;。您的Iterable 要求Stat 不仅仅是旧的Stat&lt;?&gt;,而是Stat&lt;? extends Number&gt;。您必须将您的 getPercentiles() 更改为 Map&lt;Double, ? extends Stat&lt;? extends Number&gt;&gt;

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 这是我在这些情况下会做的事情:

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();
    }
}

【讨论】:

  • 有趣的是,这在 Eclipse 中也不起作用;我尝试了几种变体。但是,这有效(删除“?扩展”): public static Map> getPercentiles() { return null; }
  • 我个人不喜欢使用? extends 表示法。我会使用Stat&lt;Number&gt;,如果有人想在其中添加Stat&lt;Double&gt;Stat&lt;BigInteger&gt;,我不在乎他们做了什么。
  • @glowcoder:这行不通,Stat 不是 Stat 的子类型。它必须是丑陋的'?扩展'...
  • @emboss 你似乎是正确的。我会调整它说我宁愿使用支持泛型的类。作为一个例子,我将编辑一个小代码来说明(经过一些修改后)我更喜欢如何使用泛型和多态性。 (显然,如果我正在使用的库不支持它,那么我无能为力!)
【解决方案3】:

它不能在 javac 中编译。 (将静态添加到 getPercentiles 后)

弄清事实;不要浪费别人的时间。

今天的孩子,ADD太多了。

【讨论】:

  • 嗯……显然你是对的;我试图创建一个从原本庞大的构建中提取的小型可重现案例,并且该构建肯定可以编译(这令人费解)。我还验证了小型可重现案例在 Eclipse 中无法编译,但您是对的,我没有通过 javac 运行小型案例。它确实给出了编译错误,让我想知道为什么大型构建会成功。我现在必须深入研究。
猜你喜欢
  • 2015-02-27
  • 1970-01-01
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 2012-01-09
  • 1970-01-01
相关资源
最近更新 更多