通用的 for-each 循环有困难

Difficulty with generic for-each loop

我在编译 foreach 循环时遇到问题。我很确定这是我的泛型处理的问题,因为错误是对象兼容性问题。我已经搜索了解决方案,但找不到任何解决问题的方法。

这是定义 Iterable adjList 的代码。

public class Graph<V,E> { 
    private SinglyLinkedList<Vertex<V>> vertices = new SinglyLinkedList<>();
    protected class Vertex<V> {
        private SinglyLinkedList<Edge<E>> adjList = new SinglyLinkedList<>();
        public void addEdge(Edge<E> e) {adjList.addLast(e);}  
        public Iterable<Edge<E>> adjList() {
            return (SinglyLinkedList<Edge<E>>) adjList;
        }
    }
    public Iterable<Edge<E>> edges(Vertex<V> v) {
        return v.adjList;
    //... Edge<E> is also a nested class
    public Iterable<Vertex<V>> vertices() {return vertices;}
}

adjList 实际上是可迭代的,因为 SinglyLinkedList 是:

public class SinglyLinkedList<T> implements Iterable<T> {
    //... 
    private class ListIterator implements Iterator<T> {
    // ... next(), hasNext()
    }
    public Iterator<T> iterator() {return new ListIterator();}
}

此迭代器在其他情况下工作正常,包括其他 foreach 循环。这是它不起作用的地方(来自不同 class 的主要方法):

Graph<String, Integer> testgraph = createGraph("testgraph.txt");
//createGraph add some vertices and edges to testgraph
for (Vertex v : testgraph.vertices()) { 
    for (Edge e : testgraph.edges(v)) {   //<--- problem here
            System.out.print(e.getElement());
        }       
    }
}

错误是"incompatible types: Object cannot be converted to Graph.Edge."

问题: 为什么 testgraph.edges(v) 返回对象列表而不是边?我真的很茫然。

此外,

for (Edge e : v.adjList()) 

也不起作用,同样的错误,并且在 Edge 之后在菱形括号中添加 "Integer" 也无法编译。这确实有效,但我真的想避免这种可怕的转换:

for (Edge e : ((Graph<String,Integer>.Vertex<String>)v).adjList())    

非常感谢任何想法。

您使用的 VertexEdge 没有任何参数化,使它们有效 Vertex<Object>Edge<Object>.

public Iterable<Edge<E>> edges(Vertex<V> v) {
    return v.adjList;
}

EdgeVertex 都需要指定 Type

for (Edge<Integer> e : ((Graph<String,Integer>.Vertex<String>)v).adjList())  

以上是不是可怕的转换,它们是泛型所期望的类型。

你有两个选择:

要么在所有地方指定类型,要么在任何地方不指定它们,完全删除它们。

问题是您将 Vertex<V>Edge<E> 声明为 Graph<V,E> 的内部 class。这意味着 Vertex 的每个实例都绑定到参数化 class Graph 的实例。因此,当您尝试在 Graph 实例之外编写 Vertex<Integer> 时,对于 Graph 的原始类型,这意味着 Graph.Vertex<Integer>。这就是编译器抱怨的原因。

您的选择是:

  1. 将 class 声明为 Vertex<V>Edge<E>static。然后你就可以写成 Vertex<String>Edge<Integer>.
  2. VertexEdge 中删除类型参数并将它们称为 Graph<String,Integer>.VertexGraph<String,Integer>.Edge