我正在尝试使用泛型来实现图,并且我想对节点和节点内的数据都使用泛型参数。如果我以第一种方式进行操作,它将起作用,但理想情况下,我想以第二种方式进行定义。
为什么第二种方法不起作用?
//OK
public class AdjacencyListGraph<E, N extends Node<E>> {
}
//Cannot resolve symbol E
public class AdjacencyListGraph<N extends Node<E>> {
}
最佳答案
在Java泛型的上下文中,extends表示上限,而不是继承。在泛型的情况下,该词的含义会过载。
Java中引入了泛型,以使开发人员能够编写比以前更一致,更干净且更少错误的代码。这全都与开发有关,而不是执行。编译后的代码中没有泛型。但是,您可以通过反射来获取有关元空间中实际类型的一些信息,但这是元信息,而不是实际代码。
在编译期间,通用类型将被擦除,并由实际范围(https://docs.oracle.com/javase/tutorial/java/generics/genTypes.html)代替。这就是问题的根本原因。如果提供的绑定也是通用的,则编译器将无法执行类型擦除。它只是不知道在编译期间应该用哪种类型替换代码中的通用类型。所以你会得到编译错误。
//OK
public class AdjacencyListGraph<E, N extends Node<E>> {
}
无论如何,您都必须提供实际的类型E,以便编译器能够解析实际的边界并执行类型擦除。
//Cannot resolve symbol E
public class AdjacencyListGraph<N extends Node<E>> {
}
在这种情况下,您的界限也将变得通用。编译器不知道实际的类型。它可以是任何类型。因此,它无法在此处执行类型擦除,并为您提供编译错误。
另外,这里还有一些有关泛型的有用资源:
http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
https://docs.oracle.com/javase/tutorial/java/generics/index.html
第一个真的很棒。这是有关扩展字的信息,它在泛型上下文中的含义:http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Does%20extends%20always%20mean%20inheritance?