带类型参数的方法与泛型方法类型参数声明之间的理论区别是什么

时间:2018-12-15 06:51:59

标签: java 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 :(得分:1)

关于泛型的重要一点是它们是不变的。在您的情况下,这意味着即使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。现在,使用泛型的基本优点是它们可以提供类型安全性,但是获取ClassCastException意味着情况并非如此,因此泛型是不变的。

但是,当您将extends与Type参数一起使用时,它允许分配,但是您必须记住PECS(Producer Extends and Consumer Super)

在第一种情况下,您需要在类级别声明类型参数。现在,当您创建LivingThing类的实例时,必须提及类型参数,例如LivingThing<LivingThingTypes> livingList = new LivingThing();。这就是T的值。现在,由于我在前面的段落中提到的原因,编译器将期望您在create方法内发送相同的Type。

在第二种情况下,您正在创建一个新的Type参数,该参数仅绑定到该方法,在这里您告诉它create方法的V extends LivingThingType类型Class<V>类型参数现在可以接受{{ 1}}。您也可以使用相同的Type参数T来代替V,但为避免混淆,应使用与以往不同的名称。

答案 1 :(得分:0)

由于Java-Oracle-Docs中定义了此概念,因此无法正常工作。

enter image description here

(如Java Doc所说) 给定两个具体的类型A和B(例如,Number和Integer),无论A和B是否相关,MyClass与MyClass没有关系。 MyClass和MyClass的共同父对象是Object。