通用:为什么使用“类 A <E 扩展超类>”代替“类 B<超级类>”?

2022-09-04 07:44:18

我正在试验Java泛型。我知道使用Java泛型,我们可以创建只处理特定类型的类和方法。这样就可以在编译时检测编程错误。

我的问题可能听起来很奇怪。为什么使用 代替 ?请看下面的代码。E extends SuperclassSuperclass

class Hunter <E extends Animal>{}

class Keaper <Animal>{}
    /*edit: as AR.3 and other pointed out, Keaper<Animal> is the same as Keaper<E>.
 Animal  is just a type parameter here*/

class Animal{}

class Cat extends Animal{}

class Dog extends Animal{}


public class TestGeneric {
    public static void main(String[] args) {
        Hunter<Cat> hunter1 = new Hunter<>();
        Hunter<Dog> hunter2 = new Hunter<>();
        Hunter<Animal> hunter3 = new Hunter<>();

        ArrayList<Hunter> hunters=  new ArrayList<>();
        hunters.add(hunter1);
        hunters.add(hunter2);
        hunters.add(hunter3);

        Keaper<Cat> keaper1 = new Keaper<>();
        Keaper<Dog> keaper2 = new Keaper<>();
        Keaper<Animal> keaper3 = new Keaper<>();
//Edit: as AR.3 and others pointed out, Keaper<String> is also legal here.

        ArrayList<Keaper> keapers=  new ArrayList<>();
        keapers.add(keaper1);
        keapers.add(keaper2);
        keapers.add(keaper3);
    }
}

我觉得差不多和一样,除了第一个可能提供更多的信息。有什么想法吗?E extends AnimalAnimal


答案 1

实际上,正如类的定义中所声明的那样,它只是一个类型参数(只使用一个字母会更常规,例如)。因此,这是一个完全不同的可能类型参数范围:该类可以接受任何类型作为参数,而不仅仅是s。你可以写,它会编译得很好,这显然不是你想要的。AnimalKeaperKeaper<T>KeaperAnimalKeaper<String>

你打算做的事情对于泛型是不可能的:你不能强迫一个类是泛型的,只有一个可能的类型参数与它相关联。您可以做的是将关联类型的范围限制为扩展特定类型的任何类型,例如,您已经对类进行了此操作。Hunter

此外,正如@JHH的注释中提到的,您应该避免在列表中用作原始类型,否则代码将不是完全泛型的。而不是你可以写.KeaperArrayList<Keaper> keapers = new ArrayList<>()ArrayList<Keaper<? extends Animal>> keapers = new ArrayList<>()


答案 2

通常,当您想要保留 in 参数的特定类型时,会使用。请考虑以下示例:extends

public class TestGeneric {

    public static <T extends Animal> T changeExtendedAnimal(T extendedAnimal) {
        return extendedAnimal;
    }

    public static Animal changeAnimal(Animal animal) {
        return animal;
    }

    public static void main(final String[] args) {
        Cat changedCat1 = changeExtendedAnimal(new Cat()); //Compiles fine. 
        Cat changedCat2 = changeAnimal(new Cat()); //Won't compile: Type mismatch: cannot convert from Animal to Cat
    }
}

在这里,该方法使用extend,因此编译器知道,如果您使用.
另一方面,使用该方法,编译器无法知道这一点,并且您会收到编译时错误。changeExtendedAnimal()CatCatchangeAnimal()


推荐