Ограниченные подстановочные знаки и добавление новых элементов в очередь - PullRequest
1 голос
/ 16 июня 2020

На днях у меня возникли проблемы с пониманием конкретного примера из учебника, связанного с ограниченными подстановочными знаками и тем, как они используются в сочетании с очередью.

Пример начинается с настройки тривиальной иерархии наследования:

class X {
    int i;
    X(int i) { this.i = i; }
}

class Y extends X {
    int i;
    Y(int i){ this.i = i; }
}

class Z extends Y {
    int i;
    Z(int i) { this.i = i; }
}

Основной класс содержит метод stati c, который принимает Queue с определением подстановочного знака, ограниченным сверху, и добавляет случайное количество новых элементов.

public class Wildcards {

    static void rtn(Queue<? extends Y> q) {
        q.add(new Y(5));
        q.add(new Z(5));
    }

    public static void main(String[] args) {
        Queue<Y> q = new LinkedList<>();
        rtn(q);
    }
}

Мое понимание этого конкретного определение подстановочного знака: «Разрешить добавление элементов к q, которые либо относятся к типу Y, либо к типу Y. Таким образом, q.add(new Y(5)) будет таким же законным, как q.add(new Z(5)). Однако компилятор жалуется в обоих случаях : Required type: capture of ? extends Y - Provided Y/Z.

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

Большое спасибо за вашу помощь!

1 Ответ

0 голосов
/ 16 июня 2020

Хорошо, во-первых, ваша иерархия классов нарушена - это не будет компилироваться. Помните, что базовый класс становится «частью» вашего производного класса. Это означает: а) у вас есть три разных 'i' (по одному в каждом классе) б) вы не инициализируете i в своем суперклассе, потому что у вас нет конструктора по умолчанию (без аргументов), и у вас нет позвоните super (i). Давайте исправим это:

class X {
    int i;
    X(int i) { this.i = i; }
}

class Y extends X {
    Y(int i) { super(i); }
}

class Z extends Y {
    Z(int i) { super(i); }
}

Теперь к собственному вопросу: всегда помните PECS - Producer extends, Consumer super Это означает, что если у вас есть, например, коллекция, которую вы хотите запросить, т.е. для получения результатов из в типобезопасном вопросе вам необходимо использовать границы с extends . Если вы хотите использовать значения, например, поместить что-то в коллекцию, используйте super.

Почему? Таким образом, «super» и «extends» - это верхний и нижний пределы:

Для «потребления» <? extends Y> означает «Я буду принимать только классы, которые расширяет Y, а <? super Y> означает:« Я буду принимать только классы, где Y » является суперклассом ".

В вашем случае вы пишете метод, который должен принимать Queue<Y> или Queue<Z> - поэтому вы говорите:« Мои методы должны принимать очереди типов, где Y - супер введите "

Это будет работать:

public class Wildcards {

    static void rtn(Queue<? super Y> q) {
        q.add(new Y(5));
        q.add(new Z(5));
    }

    public static void main(String[] args) {
        Queue<Y> q = new LinkedList<>();
        rtn(q);
    }
}

См. https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

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