【问题标题】:Java code fails in Intellij but not in eclipse, with ambiguous method errorJava 代码在 Intellij 中失败,但在 eclipse 中失败,方法不明确
【发布时间】:2020-02-13 14:56:32
【问题描述】:

我有以下 Java 类(带有嵌套类/接口)。从 Eclipse(版本:2019-09 R (4.13.0))中运行 main 方法时,我得到以下输出:

java.version: 1.8.0_241
PageA.m3() called 

这是 Eclipse 使用的命令行:

/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/bin/java -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:52180 -javaagent:/Users/*****/eclipse/java-2019-09/Eclipse.app/Contents/Eclipse/configuration/org.eclipse.osgi/222/0/.cp/lib/javaagent-shaded.jar -Dfile.encoding=UTF-8 -classpath <a-list-of-.jar-files> _play.PageTest

在 Intellij(IDEA 2019.3.3(社区版))中运行相同的代码时,我得到以下输出:

src/main/java/_play/PageTest.java:13: error: reference to m1 is ambiguous
                .m1(pageAorB -> ((SpecialPage<?>) pageAorB).m3());
                ^
  both method m1(Consumer<T#1>) in Page and method m1(Consumer<T#2>) in AbstractPage match
  where T#1,T#2 are type-variables:
    T#1 extends Page<T#1> declared in interface Page
    T#2 extends Page<T#2> declared in class AbstractPage

为什么我在 Intellij 中出现此错误,但在 Eclipse 中却没有?有没有办法解决这个问题,让它在 Intellij 中运行而不会出错?

这是 Java 类:

package _play;

import java.util.function.Consumer;
import java.util.function.Function;

public class PageTest {

    public static void main(String[] args) {
        System.out.println("java.version: " + System.getProperty("java.version"));

        new PageC()
                .m2(pageC -> (1 == 1 ? new PageA() : new PageB()))
                .m1(pageAorB -> ((SpecialPage<?>) pageAorB).m3());
    }

    public static interface Page<T extends Page<T>> {
        T m1(Consumer<T> c);
        <R> R m2(Function<? super T, ? extends R> f);
    }

    public static abstract class AbstractPage<T extends Page<T>> implements Page<T>{
        @Override
        public T m1(Consumer<T> c){
            c.accept(self());
            return self();
        }

        @Override
        public final <R> R m2(Function<? super T, ? extends R> f) {
            return f.apply(self());
        }

        abstract protected T self();
    }

    public static interface SpecialPage<T extends Page<T>> extends Page<T> {
        T m3();
    }

    public static class PageC extends AbstractPage<PageC> {

        @Override
        protected PageC self() {
            return this;
        }
    }

    public static class PageB extends AbstractPage<PageB> implements SpecialPage<PageB> {
        @Override
        public PageB m3() {
            System.out.println("PageB.m3() called");
            return this;
        }

        @Override
        public PageB self() {
            return this;
        }
    }

    public static class PageA extends AbstractPage<PageA> implements SpecialPage<PageA> {
        @Override
        public PageA m3() {
            System.out.println("PageA.m3() called");
            return this;
        }

        @Override
        public PageA self() {
            return this;
        }
    }
}

编辑 在这种情况下,Page 接口和 AbstractPage 类位于客户端无法更改的库中。但是客户端应该能够扩展 Page 接口。

【问题讨论】:

  • 您使用的是 Maven 还是 Gradle?可以试试命令行吗?
  • Gradle。我会尝试命令行...并报告。
  • 从 gradle 命令行运行(使用类型为 JavaExec 的任务)我得到与 Intellij 中相同的错误
  • 在 Eclipse 中运行时,使用的命令行是什么?它应该在输出窗口中,您可以将其添加到问题中吗?否则不可能知道项目是如何在 IDE 中运行的。
  • 问题是,是Eclipse编译器(4.13)还是javac(1.8.0_241)对(“Eclipse使用的命令行”是运行它,不要编译它,在这里没关系)。我猜,因为这里的T 相同,所以Eclipse 是对的(interface Page&lt;T extends Page&lt;T&gt;&gt; 可以简化为interface Page&lt;T&gt;AbstractPage&lt;T extends Page&lt;T&gt;&gt; implements Page&lt;T&gt;AbstractPage&lt;T&gt; implements Page&lt;T&gt;,对吧?)。 @鲍里斯@etxalpo

标签: eclipse generics intellij-idea javac ecj


【解决方案1】:

问题是,IntelliJ和Gradle默认使用的Eclipse编译器(ecj)是4.13版还是javac 1.8.0_241,对吗?

javac 的错误消息说它不明确,因为在AbstractPage 中,类型变量T 指的是AbstractPage 的类型变量(命名为T),也指的是@987654327 的不同类型变量@(也称为 T)。但实际上,两个类型变量都引用了同一个类型,并不是因为它们命名相同,而是因为AbstractPage实现了Page&lt;T&gt;。这不是模棱两可的,javac 在这里错误地给出了编译错误。

作为javac 错误的解决方法,您可以执行以下操作之一:

  • 在 IntelliJ 和 Gradle 中也可以使用 Eclipse 编译器
  • 重写main方法中的代码使用变量SpecialPage&lt;? extends Page&lt;?&gt;&gt;作为中间结果这样javac就不需要推断了:

    SpecialPage<? extends Page<?>> pageAorB = new PageC().m2(pageC -> (1 == 1 ? new PageA() : new PageB()));
    pageAorB.m1(specialPage -> ((SpecialPage<?>) specialPage).m3());
    

【讨论】:

  • 虽然这些涉及类型推断和重载的问题对于许多聪明的 Java 开发人员而言通常过于复杂,无法准确掌握,但在这种特殊情况下,javac 本身给了我们一个提示,两者之间不能有歧义@ 987654338@ 方法:javac 没有抱怨 @Override 注释。
  • @howlger 感谢建议的解决方法,但它不适用于我的用例。 Page 和 AbstractPage 位于客户端无法更改的库中。已使用此信息更新问题。
  • @etxalpo 这个动人问题的答案也已更新。 ;)
猜你喜欢
  • 2015-09-26
  • 1970-01-01
  • 1970-01-01
  • 2014-04-04
  • 2018-11-01
  • 2019-01-20
  • 2019-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多