【问题标题】:Compilation differences between Intellij, Maven and EclipseIntellij、Maven 和 Eclipse 之间的编译差异
【发布时间】:2019-04-30 11:12:37
【问题描述】:

我有一个令人困惑的问题。首先这里是一个最小的代码示例:

public interface I {
  <T> T getValue();
}

public abstract class AC<T> {
  private T value;

  public T getValue() {
    return value;
  }

  public void setValue(T value) {
    this.value = value;
  }
}

public class C extends AC<Integer> implements I {
}

public class Main {
  public static void main(String[] args) {
    final C c = new C();
    c.setValue(1);
    final Integer i = c.getValue();
    System.out.println(i);
  }
}

当我尝试使用 javac 或 Intellij 或 Maven 编译时,我得到了错误:

C 不是抽象的,不会覆盖 I 中的抽象方法 getValue()

如果我在 Eclipse 中编译程序,它会编译成功。

谁能解释一下为什么 eclipse 可以处理这个问题而其他的不行?

这里是我的软件版本:

  • Eclipse 2018-09 (4.9.0)
  • Intellij 2018.1.3
  • Maven 3.3.1
  • Oracle JDK 8u181

更新:

我将此问题报告给 Oracle,他们可以重现此问题。这是 Oracle 编译器中的一个错误 (Java Bug Database)

【问题讨论】:

  • Maven 和 Intellij 都使用(默认情况下)Oracle JDK 的javac,而 Eclipse 有自己的 Java 编译器。哪个编译器在这里由Java Language Specification 决定。

标签: java eclipse maven intellij-idea compilation


【解决方案1】:

当您从非抽象类 C 实现接口 I 时,您需要重写抽象方法 getValue()。将您的类 C 编辑为:

public class C extends AC<Integer> implements I {
    public T getValue() {
        return value;
    }
}

或者您可以在实现 getValue() 方法时从类 AC 中实现 I。从类 C,只需扩展类 AC

public abstract class AC<T> implements I {
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
      this.value = value;
    }
}

public class C extends AC<Integer> {

}

【讨论】:

  • 这是有道理的,但并不能解释为什么 eclipse 没有抱怨它,而 maven 和 Intellij 却抱怨。
【解决方案2】:

Maven 和 Intellij 都使用(默认情况下)Oracle JDK 的 javac,而 Eclipse 有自己的 Java 编译器。

这里是哪个编译器,javac 或 Eclipse 编译器Java Language Specification 决定。

我相信 Eclipse 编译器在这里是正确的,因为您的示例结合了两个可以单独使用两个编译器而没有任何问题的东西:

  • 实现接口通过继承,例如。 g.:
public class ImplementationViaInheritance {
    public static void main(String[] args) {
        System.out.println(new C1().getClass());
    }
}

class SuperC1 {
    public void foo() {};
}

interface I1 {
    void foo();
}

class C1 extends SuperC1 implements I1 {
    // implements I1 via inheritance from SuperC1
}
public class AbstractClassWithoutAbstractMethods {
    public static void main(String[] args) {
        System.out.println(new C2().getClass());
    }
}

abstract class SuperC2 {
    public void foo() {};
}

class C2 extends SuperC2 {
    // no methods
}

【讨论】:

  • 分离的情况是有效的,但是语言规范中是否有描述,它涵盖了组合的情况?我看不到。不过,我认为 eclipse 编译器做得对。
  • Java 语言规范一般不包含组合案例。而且,错误信息没有任何意义,因为代码不包含任何抽象方法(只有一个抽象类没有任何抽象方法)。
  • 不对。来自接口的方法也是抽象方法,如果您不实现来自接口的方法,编译器将失败并显示等于错误消息。
  • 确实,它失败并显示相同的错误消息。我本来期望 "...没有实现...".
猜你喜欢
  • 1970-01-01
  • 2020-10-16
  • 2015-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多