Почему A-> B не делает Список <A>-> Список <B>?Не уберет ли это необходимость в подстановочных знаках? - PullRequest
2 голосов
/ 20 ноября 2010

Отказ от ответственности: я не профессиональный разработчик, и я не собираюсь им стать. Читая книгу о Java, так как я хотел попробовать программирование на Android, никакого предыдущего опыта работы с Java вообще не было. Я читаю эту книгу - и мне она очень нравится. Я прочитал часть главы об общих классах, дошел до того, что они упоминают подстановочные знаки, и запутался.

Если B расширяет A:

  1. List<B> не является подтипом List<A> (насколько я понимаю, они точно такие же)
  2. List<? extends B> является подтипом List<? extends A>

Последний позволяет писать функции, которые принимают аргументы общего типа, например List<? extends A>. Такая функция будет принимать аргумент либо List<B>, либо List<A>.

Теперь, на мой вопрос:

Не проще ли реализовать дженерики способом, аналогичным C ++ (в виде шаблона)? Это сделает List<B> и List<A> двумя отдельными типами, которые будут связаны ожидаемым образом. Это также позволило бы просто указать в функции, что вы ожидаете, что аргумент будет иметь тип List<A>, что позволит List<B> вписываться туда просто отлично.

Я предполагаю, что было более чем "мы ненавидим C ++, давайте изменим ситуацию" за этим :) Также вполне возможно, что я еще ничего не знаю, что делает подстановочные знаки фантастическими и полезный инструмент. Что вы думаете об этом?

Редактировать: , если вы упоминаете List<X> в своем ответе, не забывайте использовать обратные метки, чтобы <X> не интерпретировался как HTML-тег.

Ответы [ 5 ]

5 голосов
/ 20 ноября 2010

Есть простая причина.

Предположим, у вас есть переменная типа List<A>.Предположим, что List<B> действительно был подтипом List<A>.

Это означает, что когда это будет законно:

List<A> a_list;
a_list = new List<B>(); //allowed when List<B> is subtype of list<A>
a_list.add(new A()); // WOAH!

Когда я говорю WOAH, происходит следующее: Вы добавляете элемент типа A в a_list.Поскольку a_list был объявлен как List<A>, это должно быть разрешено.Но подождите: a_list указывает на что-то типа List<B>.

Итак, теперь мы добавляем в список что-то типа A, в котором должны храниться только элементы типа B, и это явно не то, что нам нужно, поскольку A не является подклассом B!

1 голос
/ 20 ноября 2010

Если бы List был подтипом List , следующий код был бы допустимым, так как java действительно удаляет большую часть общего волшебства во время компиляции.(Если это было хорошее решение или нет, это другая тема).

public void addNewAToList(List<A> list) {
    list.add(new A());
}


public static void main(String[] args) {
    List<B> listB = new LinkedList<B>();
    addNewAToList(listB);       // <--- compiler error
    for (B b : listB) {         // <--- otherwise: there is an A in the list.
        System.out.println(b);
    }
}
0 голосов
/ 20 ноября 2010

Статическая типизация диктует, что подтип должен поддерживать все операции своего супертипа.

List<Fruit> поддерживает вставку Fruit объектов.

List<Banana> нет - вы не можете вставить произвольные фрукты в List<Banana>, только бананы.

Следовательно, List<Banana> не является подтипом List<Fruit>.

0 голосов
/ 20 ноября 2010

Ну, Онлайн-компилятор Comeau c ++ не работает на этом:

template<typename T> class List {
};

class A {
};

class B: public A {
};

void function(List<A> listA) {
}

int main(int argc, char** argv) {
    List<A> a;
    List<B> b;

    function(a);
    function(b);
}

, выдавая эту ошибку:

"ComeauTest.c", line 18: error: no suitable user-defined conversion from "List<B>" to
          "List<A>" exists
  function(b);

Так что C ++ и Java похожи при работе сэти виды типов.

0 голосов
/ 20 ноября 2010

Проблема в том, что если у вас class C extends A и вам дано List<A>, вы можете поставить C, потому что C - это A. Но если Java позволил вам просто дать методу List<B>, тогда вы помещаете C в список B с. И C - это не B, поэтому в будущем произойдет ошибка. Решение подстановочных знаков Java не позволяет вам добавлять ничего, кроме null к List<? extends A>, что избавляет вас от этой ошибки.

...