Java код не работает в Intellij, но не в затмении, с неоднозначной ошибкой метода - PullRequest
2 голосов
/ 13 февраля 2020

У меня есть класс Java ниже (с вложенными классами / интерфейсами). При запуске метода main из Eclipse (Версия: 2019-09 R (4.13.0)) я получаю следующий вывод:

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 (Community Edition)) я получаю следующий вывод:

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, но не в Затмение? Есть ли способ решить эту проблему, чтобы он работал без ошибок в 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;
        }
    }
}

EDIT В этом случае страница Интерфейс и класс AbstractPage находятся в библиотеке, которую клиент не может изменить. но клиент должен иметь возможность расширять интерфейс страницы.

1 Ответ

1 голос
/ 13 февраля 2020

Вопрос в том, является ли Eclipse-компилятор (ecj) версии 4.13 или javac 1.8.0_241, который по умолчанию используется IntelliJ и Gradle?

Сообщение об ошибке javac говорит о его неоднозначности, поскольку в AbstractPage переменная типа T относится к переменной типа AbstractPage (с именем T), а также к переменной другого типа Page (также называется T). Но на самом деле обе переменные типа относятся к одному и тому же типу , не потому, что они названы одинаково, а потому, что AbstractPage реализует Page<T>. Это не является двусмысленным и javac ошибочно дает здесь ошибку компиляции.

В качестве обходного пути этой ошибки javac вы можете сделать одно из следующих действий:

  • Используйте компилятор Eclipse также в IntelliJ и Gradle
  • Перепишите код в методе main , используя переменную SpecialPage<? extends Page<?>> для промежуточного результата , чтобы javac не нужно делать вывод:

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