簡體   English   中英

Java Records 是否適合表示圖的節點?

[英]Are Java Records suitable to represent the nodes of a graph?

表示圖的經典方法之一(如在圖論中)是:

class Node {
  String value;
  List<Node> children;

  // constructor, equals, etc. are omitted
}

問題是關於使用Java 14 中引入的新記錄功能

具體來說,對於像 DFS 這樣的算法使用如下聲明是否有任何潛在的缺陷:

record Node(String value, List<Node> children) {}

一個潛在的問題是關於記錄提供的equals / hashCode方法。 我想,在Node的情況下,記錄提供的實現可能會導致無限遞歸(StackOverflow)。

例如,考慮下面使用Set集合的代碼。

import java.util.*;

class SO {
    
  static void dfs(Node n, Set<Node> visited) {
    if (n == null) return;
    System.out.println("visited " + n.value());
    for (Node child : n.children()) {
      if (visited.contains(child)) continue;
      visited.add(child);
      dfs(child, visited);
    }
  }

  public static void main(String[] args) {
    var a = new Node("a", new ArrayList<>());
    var b = new Node("b", new ArrayList<>());
    a.children().add(b);
    b.children().add(a);
    dfs(a, new HashSet<>());
  }

}

record Node(String value, List<Node> children) {}

此代碼導致 StackOverflow:

% java SO.java
visited a
Exception in thread "main" java.lang.StackOverflowError
    at Node.hashCode(SO.java:25)
    at java.base/java.util.ArrayList.hashCodeRange(ArrayList.java:595)
    at java.base/java.util.ArrayList.hashCode(ArrayList.java:582)
    at java.base/java.util.Objects.hashCode(Objects.java:103)
    at Node.hashCode(SO.java:25)
    ... <omitted> ...

這是否意味着使用記錄通常不適合圖形算法? 如果不是,如何在與記錄一起使用時正確實現此類算法?

堆棧跟蹤揭示了堆棧溢出錯誤的原因。

問題是您創建的循環關系 - a 是 b 的孩子,b 是 a 的孩子 - 在計算節點的哈希碼時會導致無限循環。

record使用所有字段計算其哈希碼。 反過來, List使用其所有元素的哈希碼計算其哈希碼。 因為 a 的列表包含 b,而 b 的列表包含 a,所以傳遞給 HashSet 方法的每個對象的哈希碼計算都會無限下降。

解決方法是覆蓋equals()hashCode()以不涉及children ,可能通過return super.hashCode(); ETC

或者不要定義循環關系。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM