java中邻接表声明为list

Java中邻接表若声明为 List extends Node>,这种写法本身是**不合法的语法**,且与PECS原则的正确用法相悖——它混淆了通配符作用对象(应修饰集合类型,而非元素类型)。
邻接表不该用 List extends Node>
你写的 List<edge extends="" node="">></edge> 看似想表达“边是节点的子类”,但 Java 泛型不支持在尖括号内写 extends 修饰元素类型;? extends Node 是通配符,只能出现在**集合类型参数位置**,例如 List extends Node>,表示“一个元素类型为 Node 或其子类的列表”,但它描述的是整个列表的类型约束,不是边类的定义方式。
真正的邻接表建模,应区分两类泛型角色:
-
节点类型是固定的基类或接口(如
Node),边通常不继承节点,而是关联两个节点(如Edge<n extends node></n>); -
邻接表本身是容器,比如
List<edge>></edge>或更灵活地用List extends Edge<node>></node>——但后者仅在只读场景有意义。
读取邻接表时才适用 ? extends T
当你遍历邻接表、只从中获取边并调用其方法(如 getFrom()、getTo()),且这些方法返回类型可统一为 Node 或其公共父类型时,才考虑 PECS 的 ? extends:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 方法签名示例:
void traverse(List extends Edge<node>> edges)</node>; - 你可以安全调用
edges.get(i).getFrom(),只要getFrom()返回Node或其子类; - 但不能往该列表里
add()任何边,因为编译器不知道底层实际是ArrayList<directededge></directededge>还是ArrayList<weightededge></weightededge>。
写入邻接表时用 ? super Edge
如果某个工具方法负责向邻接表批量添加边,且希望兼容不同边类型的列表(如 List<edge></edge>、List<object></object>、List<weightededge></weightededge>),就该用下界:
- 方法签名:
void addEdges(List super Edge> target, Collection<edge> newEdges)</edge>; - 可以安全调用
target.add(e),因为所有接受Edge的列表,其元素类型至少是Edge的父类; - 但取出元素时只能当
Object处理,无法直接当Edge用——除非你额外做类型检查或强制转换。
实际图结构推荐写法
比起强行套用通配符,更清晰健壮的做法是:
- 定义边为泛型类:
class Edge<n extends node> { N from; N to; }</n>; - 邻接表用具体类型:
List<edge>></edge>或Map<mynode list>>></mynode>; - 通用遍历工具方法才引入 PECS:
<n extends node> void printEdges(List extends Edge<n>> list)</n></n>。
PECS 不是用来“修饰边类”的语法糖,而是为**集合参数的读写契约**提供编译期保障。用错位置,不仅编译不过,还会掩盖真实的设计意图。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










