Компиляция не удалась, когда верхний предел подстановочный знак используется с нижним

Ситуация: я делаю библиотеку конфигурации с интерфейсом Config, который представляет данные, и интерфейсом парсера, подобным этому:

public interface Parser<C extends D, D extends Config> {
    C parse(File f);
    void parse(File f, D destination);
}

Анализатор должен иметь возможность анализировать данные в новый объект Config (C) или существующий (D). C расширяет D, потому что логично, что мы можем создать C вручную и проанализировать в нем данные. И, конечно, D расширяет Config, потому что мы анализируем конфигурации.

Допустим, у нас есть класс MyConfig, который реализует Config (но он также может быть универсальным "T extends Config"), и мы хотим, чтобы Parser мог его создавать и анализировать. Давайте следовать правилу PECS:

  • Наш синтаксический анализатор может анализировать MyConfig, но, возможно, его супертипы тоже => Я должен использовать "? Super MyConfig"
  • Наш парсер может создать MyConfig, но, возможно, он на самом деле создает подтип => я должен использовать "? Extends MyConfig"

Поэтому я в конечном итоге с этим:

Parser<? extends MyConfig, ? super MyConfig> parser;

Но хотя IntelliJ ни на что не жалуется, компиляция (javac 1.8.0_131) завершается с этой ошибкой:

введите аргумент? расширяет пакет.MyConfig находится за пределами переменной типа C

Что странно, потому что "некоторый подтип MyConfig", очевидно, является подтипом "некоторого супертипа MyConfig", верно?

Эта проблема возникает только при использовании обоих подстановочных знаков. Кроме того, использование другого универсального типа вместо верхней границы работает:

// All these are fine
Parser<? extends MyConfig, MyConfig>
Parser<MyConfig, ? super MyConfig>
<J extends MyConfig> void test(Parser<J, ? super MyConfig> parser)

Что мне здесь не хватает? И что я могу сделать с моим производителем-потребителем Parser?

РЕДАКТИРОВАТЬ: я нашел что-то еще более запутанным: использование подинтерфейса Config вместо подкласса работает, то есть это прекрасно компилируется:

interface SpecialConfig extends Config {}
Parser<? extends SpecialConfig, ? super SpecialConfig> specialParser;

0 ответов

Другие вопросы по тегам