返回
在Java泛型中实现自引用:解决循环引用问题
java
2024-03-18 15:02:43
Java泛型中的自引用(递归):解析问题
自引用泛型简介
泛型是一种强大的编程技术,它允许我们创建类型安全的代码,而无需明确指定类型参数。在 Java 中,泛型可以通过<
和 >
符号来表示,其中泛型类型变量位于符号之间。
在某些情况下,我们可能需要使用自引用泛型,也就是泛型类型变量引用它自己。这被称为泛型的递归,并且允许我们创建能够自我参数化的类型。
问题
在 Java 中,实现泛型递归可能会遇到一些挑战。让我们考虑以下示例:
public interface Node<E extends Edge> {
List<E> getOutgoingEdges();
List<E> getIncomingEdges();
}
public interface Edge<N extends Node> {
N getSource();
N getTarget();
}
编译器将拒绝编译此代码,因为它导致了循环引用。为了解决这个问题,我们可以尝试以下方法:
public interface Node<E extends Edge<?>> {
List<E> getOutgoingEdges();
List<E> getIncomingEdges();
}
public interface Edge<N extends Node<?>> {
N getSource();
N getTarget();
}
然而,这种方法的问题是,它允许使用两个类来实现这些接口:
public class NodeImpl<E extends Edge<NodeImpl<E>>> implements Node<E> {
// ...
}
public class EdgeImpl<N extends Node<EdgeImpl<N>>> implements Edge<N> {
// ...
}
这并不是我们想要的,因为我们希望强迫 NodeImpl 和 EdgeImpl 仅能够实现特定的 Node 和 Edge 类型。
解决方案
正确的解决办法是:
public interface Node<E extends Edge<? super Node<E>>> {
List<E> getOutgoingEdges();
List<E> getIncomingEdges();
}
public interface Edge<N extends Node<? super N>> {
N getSource();
N getTarget();
}
这些接口使用? super
通配符,它允许类型参数引用其自身或其任何超类。这确保了 NodeImpl 和 EdgeImpl 只能使用兼容的 Node 和 Edge 类型进行实例化。
实例化
我们可以按如下方式实例化 NodeImpl 和 EdgeImpl:
NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<EdgeImpl<NodeImpl<Edge