我正在尝试使用Java泛型。我理解Java泛型,我们可以创建只处理特定类型的类和方法。这样可以在编译时检测编程错误。
我的问题可能听起来很奇怪。为什么要使用E extends Superclass
代替Superclass
?请看下面的代码。
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 Animal
几乎与Animal
相同,但第一个可能会提供更多信息。有什么想法吗?
答案 0 :(得分:15)
实际上在Animal
类的定义中声明的Keaper
只不过是类型参数(对于它来说,使用一个字母就更常规了,比如Keaper<T>
)。因此,它是一个完全不同的可能类型参数范围:Keaper
类可以接受任何类型作为参数,而不仅仅是Animal
s。您可以编写Keaper<String>
并且编译正常,这显然不是您想要的。
使用泛型无法实现您的目的:您不能强制某个类是通用的,只有一个可能的类型参数与之相关联。你可以做的是限制相关类型的范围,例如,扩展某种类型的任何类型,你已经使用Hunter
类做了。
同样如@JHH评论中所述,您应该避免在列表中使用Keaper
作为原始类型,否则代码将不是完全通用的。您可以写ArrayList<Keaper> keapers = new ArrayList<>()
而不是ArrayList<Keaper<? extends Animal>> keapers = new ArrayList<>()
。
答案 1 :(得分:10)
通常,当您想要保留in-parameter的特定类型时,您将使用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
}
}
此处changeExtendedAnimal()
方法使用extends,因此如果您使用Cat
调用方法,编译器会知道您将返回Cat
。
另一方面,使用changeAnimal()
方法,编译器无法知道这一点,并且您会收到编译时错误。