Java Generics, тип теряется - PullRequest
       12

Java Generics, тип теряется

0 голосов
/ 29 декабря 2018

Следующий пример, хотя и кажется правильным, не скомпилируется (Eclipse Neon 3, Java 1.8):

class Test {    

    public static class SomeForm<IF extends SomeForm<IF>> {

    }

    public static class BaseFF<IF extends SomeForm<IF>> {

    }

    public static class AuxFF<IF extends SomeForm<IF>>
            extends BaseFF<IF> {

    }

    public interface Interface<IF extends SomeForm<IF>, FF extends BaseFF<IF>> {
        FF getFF1();        
    }

    public static class ZBaseUnit<IF extends SomeForm<IF>, FF extends BaseFF<IF>>
            implements Interface<IF, FF> {

        @Override
        public FF getFF1() {
            return null;
        }

    }

    public static class ZMyUnit<IF extends SomeForm<IF>, FF extends AuxFF<IF>>
            extends ZBaseUnit<IF, FF> {

    }

    public static class ZMyCheck<IF extends SomeForm<IF>, U extends ZMyUnit<IF, ?>> {
        U unit;

        void f() {
            BaseFF<IF> ff1 = unit.getFF1();
        }

    }

}

Eclipse говорит (в строке внутри метода f ()):

«Несоответствие типов: невозможно преобразовать из захвата # 2-of? В Test.BaseFF».

Однако, если я удалю метод getFF1 из интерфейса Interface (и аннотацию @Override в классе ZBaseUnit)компилируется.Есть ли какая-то логика за этим?Интуитивно понятно, что FF, переданный в Interface, такой же, как FF, переданный в ZBaseUnit, поэтому не должно быть никакой разницы ...

Кроме того, при добавлении метода в ZMyUnit не возникает ошибка:

void f() {
    BaseFF<IF> ff1 = getFF1();
}

Буду признателен за любую помощь!

Ответы [ 2 ]

0 голосов
/ 31 декабря 2018

В отношении класса ZMyCheck и инициализации переменной в пределах ...

    public static class ZMyCheck<IF extends SomeForm<IF>, U extends ZMyUnit<IF, ?>> {
        U unit;

        void f() {
            BaseFF<IF> ff1 = unit.getFF1();
        }

    }

... в конечном итоге правильность сводится к типу выражения unit.getFF1()и является ли этот тип подтипом BaseFF<IF>.Тип этого выражения является функцией типа переменной экземпляра unit, которая в результате стирания типа интерпретируется как верхняя граница переменной типа U, то есть ZMyUnit<IF, ?>.

Что касается типа unit.getFF1(), то JLS указывает, что

Типы полей, методов и конструкторов [типа] являются типами полей,методы и конструкторы в преобразовании захвата [этого типа].

( JLS 10, 4.5.2 )

Поэтому нам необходимо определить захватпреобразование типа ZMyUnit<IF, ?>, как указано в раздел 5.1.10 .Спецификация здесь становится довольно технической, но суть в том, что верхняя граница параметра второго типа ZMyUnit учитывает, так что происходит преобразование захвата в тип ZMyUnit<IF, AuxFF<IF>>.Интерпретируемый в соответствии с этим типом, метод getFF1() возвращает тип AuxFF<IF>, который подлежит расширяющемуся ссылочному преобразованию в тип BaseFF<IF>, и это то, что нужно.

Таким образом, как @JohnMcClane также ответилКомпилятор Eclipse неверно отклоняет представленный код.Добавление соответствующей верхней границы к шаблону, кажется, обходит эту проблему, не изменяя семантику кода относительно JLS.

0 голосов
/ 31 декабря 2018

Если вы добавите этот проверочный код к своему классу

public static class GF extends SomeForm<GF> {
}

public static void main(String[] args) {
    ZMyCheck<GF, ZMyUnit<GF, AuxFF<GF>>> z = new ZMyCheck<>();
    z.unit = new ZMyUnit<>();
    z.f();
    System.out.println("OK");
}

и используете стандартные инструменты командной строки JDK (javac и java), тогда код будет скомпилирован и успешно выполнен.То же самое верно, если вы используете NetBeans (я не собираюсь каким-либо образом продвигать NetBeans).

Следовательно, проблема связана с Eclipse.Eclipse имеет свой собственный встроенный компилятор, и кажется, что вы обнаружили одну из его слабых сторон (возможно, вам нужно подать отчет об ошибке).Невозможно определить, что подстановочный знак ? на самом деле относится к типу, который расширяет AuxFF<IF> (и, следовательно, BaseFF<IF>).Вы должны указать это явно:

public static class ZMyCheck<IF extends SomeForm<IF>,
    U extends ZMyUnit<IF, ? extends AuxFF<IF>>> {...}

Тогда все скомпилируется и будет работать без сбоев.

...