Какова теоретическая разница между методом с параметром типа и объявлением параметра типа метода - PullRequest
0 голосов
/ 15 декабря 2018

Привет всем, я изучаю Generics в Java.в которой я создал эту иерархию. enter image description here

Теперь я создал LivingThing класс

public class LivingThing<T extends LivingThingTypes> implements Iterable<LivingThingTypes>{
public ArrayList<T> create(Class<T> type) {
        ArrayList arrayList = new ArrayList<>();
        for (T item : list) {
            if (item.getClass().equals(type)) {
                arrayList.add(item);
            }
        }
        return arrayList;
    }
}

Итак, когда я пытаюсь получить доступ к create()метод, подобный этому коду раздела, он не работает.

livingList.create(Human.class).size();
livingList.create(Cat.class).size();
livingList.create(Hen.class).size();

Но если я поменяю метод на этот, он отлично работает

public class LivingThing<T extends LivingThingTypes> implements Iterable<LivingThingTypes>{
        public <V extends LivingThingTypes>ArrayList<V> create(Class<V> type) {
            ArrayList arrayList = new ArrayList<>();
            for (T item : list) {
                if (item.getClass().equals(type)) {
                    arrayList.add(item);
                }
            }
            return arrayList;
        }
    }

Ответы [ 2 ]

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

Это не сработало из-за этой концепции, определенной в Java-Oracle-Docs.

enter image description here

(Как говорит Java Doc) Учитывая два конкретных типа A и B (например, Number и Integer), MyClass не имеет отношения к MyClass, независимо от того, связаны ли A и B или нет.Общим родителем MyClass и MyClass является Object.

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

Важной особенностью дженериков является то, что они инвариантны.В вашем случае это означает, что хотя класс Human расширяет LivingThingTypes, но List<Human> не расширяет List<LivingThingTypes>.Таким образом, в основном вы не можете выполнить следующее задание:

List<Human> list1;

List<LivingThingTypes> list2 = list1; //compile error

Вот как создаются Дженерики.Причина в том, что у вас есть родительский класс Animal, а Dog и Cat - дочерние классы.Теперь вы создали List<Dog> и присвоили ему List<Animal>.Теперь, поскольку Animal является родительским классом Cat, вы также можете добавить кошек к List<Animal>.Хитрая итерация может дать ClassCastException.Теперь основные плюсы использования Generics в том, что они обеспечивают безопасность типов, но получение ClassCastException означает, что это не так, и, таким образом, Generics инвариантны.

Но когда вы используете extends вместе с параметром Type, тогда это позволяет присваиваниено тогда вы должны помнить PECS (Producer Extends и Consumer Super) .

В вашем первом случае у вас есть Type Parameter, объявленный на уровне класса.Теперь, когда вы создаете экземпляр класса LivingThing, вы должны упомянуть параметр типа, такой как LivingThing<LivingThingTypes> livingList = new LivingThing();.И это становится значением T. Теперь компилятор будет ожидать, что вы отправите тот же самый тип внутри метода create также по причине, которую я упомянул в предыдущем параграфе.

Во втором случае вы создаете новый параметр Type, который привязан только к методу, и здесь вы говорите ему, что V extends LivingThingType и, таким образом, теперь Class<V> аргумент типа метода create может принимать Human.class/Hen.class/Cat.class,Вы можете использовать тот же параметр типа T также вместо V, но во избежание путаницы вы должны называть их иначе, чем вы.

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