Java компилятор не может определить тип в цепочке generi c - PullRequest
4 голосов
/ 13 января 2020

Как упомянуто ниже (чтобы отметить это, поскольку я, возможно, плохо объяснил себя):

Я хочу понять принцип, лежащий в основе этого вопроса, чтобы я мог применить эти знания к реальному проблема.


ВЫПУСК ВЫПУСКА

Я работаю в системе, предназначенной для использования в качестве абстрактной библиотеки, которая будет использоваться многими подсистемами. Идея состоит в том, чтобы иметь стандартное поведение, расширяемое реализациями. Моя проблема в том, что java компилятор не может определить тип параметра метода, даже если это не имеет смысла, поскольку границы хорошо устанавливаются для каждого связанного обобщенного c класса / метода.

Ниже приведен Например, минимальный пример для воспроизведения проблемы. Я знаю, что это выглядит немного глупо в этом примере, но это из-за упрощения:

    public class Test {
    public static void main(String[] args) {
        Gen<? extends Base> gen = new HijaGen();
        gen.applyTo(Hija.EXAMPLE);
    }
    private interface Base {
        String getName();
    }
    private enum Hija implements Base {
        EXAMPLE;
        @Override
        public String getName() {
            return this.name();
        }
    }
    private interface Gen<T extends Base> {
        boolean applyTo(T base);
    }
    private static class HijaGen implements Gen<Hija> {
        @Override
        public boolean applyTo(Hija base) {
            return false;
        }
    }
}

В основном это говорит, что applyTo ожидает подкласс Base, и Hija недопустим, что с моей точки зрения делает нет смысла.

Заранее спасибо.

РЕДАКТИРОВАТЬ:

Этот код для библиотеки, так что решение не может указывать тип с тех пор его нельзя было расширять с помощью конкретных реализаций.

Я уже знаю, что если я укажу тип generi c вместо броска подстановочного знака типа, он будет отлично работать. Но мой вопрос заключается в том, как это возможно, что, хотя подклассы Hija Base и методическая фирма требуют подкласс Base, он никогда не скомпилируется ...

Я хочу понять принцип, лежащий в основе этой проблемы, чтобы я мог применить это знание к реальной проблеме.

Ответы [ 3 ]

4 голосов
/ 13 января 2020

A Gen<? extends Base> - это Gen из что-то , которое расширяет Base. Это относится к некоторым конкретным c типам Base, но мы не знаем, какие именно. На практике это означает, что вам никогда не удастся вызвать applyTo для переменной с типом Gen<? extends Base>, кроме как путем передачи значения null.

Измените свой код на

Gen<Hija> gen = new HijaGen();
gen.applyTo(Hija.EXAMPLE);

Я подозреваю вы, вероятно, скажете, что не можете этого сделать, потому что ваш код является лишь примером, а вышеприведенное невозможно в реальном коде. В этом случае вам нужно будет привести лучший пример

2 голосов
/ 13 января 2020

Я думаю, что подобная проблема объясняется в документах здесь , и проблема, которую они предлагают, состоит в том, чтобы создать помощника (или оболочку) для уточнения типов. Поэтому я думаю, вы можете попробовать добавить эту функцию:

private static <T extends Base> boolean applyTo(Gen<T> gen, T base){
    return gen.applyTo(base);
}

И изменить основную функцию следующим образом:

public static void main(String[] args) {
    boolean b = applyTo(new HijaGen(), Hija.EXAMPLE);
}
0 голосов
/ 13 января 2020

В соответствии с тем, что упомянул Карлос, есть еще один способ решить эту проблему. Его можно использовать, если вы уверены в поставщиках реализации Gen<T>.

. Здесь вместо помощника для вызова applyTo() мы определяем фабричный метод для создания экземпляра * 1005. * реализации и приведите его к Gen<Base>, что, на мой взгляд, безопасно для всех практических целей. Обратите внимание, что заводской метод get() не обязательно должен быть stati c. Остальная часть кода остается неизменной по сравнению с вашим примером.

public static void main( String[] args ){
    Gen<Base> gen = (Gen<Base>) get();
    gen.applyTo( Hija.EXAMPLE );
}

static Gen<? extends Base> get(){
    /* Create the instance of the Gen interface implementation here. */
    return new HijaGen();
}

Пояснение

Gen<? extends Base> предполагает ссылку на экземпляр реализации Gen, который использует тип, который либо Base или его подтип. Поскольку «подтип» может быть из одной из многих возможных иерархий от Base вниз (как показано на рисунке ниже), нельзя быть уверенным, что параметр, переданный методу applyTo(), имеет тот же путь дочерней иерархии, а не просто «родственник» с тем же родителем-предком Base. Вот почему он не разрешает вызов applyTo() с его ссылкой, равной Gen<? extends Base>, для параметра со ссылкой как Base.

Однако, когда ссылка является Gen<Base>, он знает, что applyTo() примет любой параметр, который является дочерним типом Base. И, следовательно, перестает беспокоиться о несоответствии типов.

Я пытался показать, что я имею в виду под разными дочерними путями иерархии. Это похоже на случай родословной.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...