【问题标题】:Declaration of generic Iterators泛型迭代器的声明
【发布时间】:2026-01-11 19:25:02
【问题描述】:

我正在编写一个名为 graph 的类,我用 Hashmap 表示有向图。我想创建一个通过以下方式打印出整个图表的方法:

key1: value13, valeue17, ..
key2: value21, ...

其中 value13 是 node1(key1) 指向的 node3 的值。 所以,对于像 1->2->3 和 2 也指向 4 的东西,我需要:

1: 2
2: 3,4

我的代码如下所示:

public class Graph<T>{
  Map<Node<T>, List<Node<T>>> graph;

  //constructors and methods

  void printGraph(){
    System.out.println(graph.keySet().iterator().next().value); // is printing 7
    Iterator itKey = graph.keySet().iterator();
    System.out.println(itKey.next()); // printing Graph$Node@15db9742
    System.out.println(itKey.next().value); //error
    while(itKey.hasNext()){
    //code
  }

  public static void main(String[] args){
    Graph<Integer> graph = new Graph<>();
    Node<Integer> n1 = new Node<>(7);
    Node<Integer> n2 = new Node<>(2);
    graph.connect(n1, n2);
    graph.printGraph();
  }
}

我的问题出现在方法printGraph() 中,我在其中定义了一个Iterator。我想要做的是创建一个迭代器 在键集上,然后为每个键创建一个迭代器,该迭代器将打印所有值。如您所见,如果我尝试打印System.out.println(graph.keySet().iterator().next().value); 我得到一个 7,这是有道理的,因为它是我在 keySet() 中的第一个键的值。如果我用另一种方式来初始化迭代器Iterator itKey = graph.keySet().iterator();,这是一个指向Node的迭代器:

System.out.println(itKey.next()); // printing Graph$Node@15db9742

虽然,如果我尝试打印它的值:

System.out.println(itKey.next().value); //error

我收到以下错误:

error: cannot find symbol
    System.out.println(itKey.next().value);
                                   ^
  symbol:   variable value
  location: class Object
1 error

这不应该是一回事吗?为什么会出现错误?

【问题讨论】:

  • 这个问题归结为如何打印Map,其中键为Node,值为List&lt;Node&lt;T&gt;&gt;
  • 其实问题更多是和迭代器打交道,它被应用在这个打印问题上,但问题并不是这样

标签: java generics iterator raw-types


【解决方案1】:

这是一个编译错误,因为您的Iterator itKey 具有原始类型;所以调用itKey.next() 将返回Object。您想为迭代器指定正确的类型,以便 iterator.next() 具有返回类型 Node

在您的代码中,只需更改 itKey 变量的类型

  void printGraph() {
    System.out.println(graph.keySet().iterator().next().value);
    // use the non-raw type here
    Iterator<Node<T>> itKey = graph.keySet().iterator();
    System.out.println(itKey.next());
    System.out.println(itKey.next().value); 
    while (itKey.hasNext()) {
      // code
    }
  }

System.out.println(graph.keySet().iterator().next().value); 行编译,因为没有类型信息丢失。查看涉及的类型:

  • graph 变量的类型为 Map&lt;Node&lt;T&gt;, List&lt;Node&lt;T&gt;&gt;&gt;
  • graph.keySet() 的类型为 Set&lt;Node&lt;T&gt;&gt;
  • graph.keySet().iterator() 具有类型 Iterator&lt;Node&lt;T&gt;&gt;
  • graph.keySet().iterator().next() 具有类型 Node&lt;T&gt;

由于最后一个next() 的类型是Node,我们可以得到它的value

【讨论】:

  • 好的,但是为什么第一行知道我的意思是什么类型?当我使用 graph.iterator().next().value;我的意思是,本质上的区别是什么?为什么一个人了解类型而另一个人不了解?
  • 我已经编辑了答案;在第一种情况下,没有类型丢失。所以我们最终在Nodes 上得到了一个迭代器。但是如果你声明Iterator(没有泛型类型)而不是Iterator&lt;Node&gt;,那么迭代器将是Objects上的迭代器;
【解决方案2】:

你的

itKey.next().value 

给出错误,因为迭代器知道value是什么。 可能itKey.next() 转换为Node 会起作用但这不是最理想的方式来打印你的图表。

您可以使用以下方法。它使用条目集来迭代 graph 映射。

printGraph 函数:

void printGraph() {
    for (Map.Entry<Node<T>, List<Node<T>>> entry : graph.entrySet()) {
        Node<T> fromNode = entry.getKey();
        System.out.print(fromNode.value + " ->");
        for (Node<T> toNode : entry.getValue())
            System.out.print(" " + toNode.value);
        System.out.println();
    }
}

main函数:

Node<Integer> n1 = new Node<>(1);
Node<Integer> n2 = new Node<>(2);
Node<Integer> n3 = new Node<>(3);
Node<Integer> n4 = new Node<>(4);
Node<Integer> n5 = new Node<>(5);

Graph<Integer> graph = new Graph<>();
graph.connect(n1, n2);
graph.connect(n1, n3);
graph.connect(n4, n5);

graph.printGraph();

哪个打印:

4 -> 5
1 -> 2 3

【讨论】:

    【解决方案3】:

    您应该提供非通用的通用迭代器。如果非泛型,则返回 Object 类型作为元素,然后您需要将其类型转换为不好的 Node,因此最好在获取 Iterator 实例时定义类型。

     Iterator<Node<T>> itKey = graph.keySet().iterator();
    
     while(itKey.hasNext()){
             System.out.println(itKey.next().value);    
    }
    

    【讨论】: