两个图之间的等于失败。怎么来?

时间:2014-05-27 18:20:26

标签: jgrapht

我试图简单地等于两个jgraphT实例并返回false,即使它们是相同的。 然后我尝试用我的实现覆盖equals:

public boolean equals(MyGraph<CustomV, CustomE> otherGraph){
    boolean result = true;

    Iterator<CustomV> vertexes = otherGraph.vertexSet().iterator();
    while(result && vertexes.hasNext()){
        result = this.containsVertex((V) vertexes.next());  
    }

    Iterator<CustomE> edges = otherGraph.edgeSet().iterator();
    while(result && edges.hasNext())
        result = this.containsEdge((E) edges.next());


    return result;
}

并且看到如果该边缘不是EXACT对象,则containsEdge()方法将失败。这很奇怪,因为我确保覆盖边缘和开关的等于方法......

编辑: 做了这个实验:

CustomV aNode = new CustomV(1,2);
myGraph.addVertex(aNode);
System.out.println(myGraph.containsVertex(aNode)); //true
System.out.println(myGraph.containsVertex(new CustomV(1,2))); //false..but should be true

并且您可以看到containsVertex()方法似乎不起作用..

EDIT2: 感谢愚蠢的怪胎我几乎解决了:我也必须覆盖hashcode()方法。 现在,这适用于Vertexes但是对于边缘我在哈希码上得到一个空指针异常,这是我的重写方法:

@Override
public int hashCode() {

    return (getSource().hashCode()+getTarget().hashcode());
}

当我尝试在图形上创建边时,我得到一个空指针(我想这里调用了hashcode()):

myGraph.addEdge(a,b);

问题是getSource()和getTarget()似乎在那一刻被调用时返回null ...如何解决? 这是异常堆栈:

  

线程“main”java.lang.NullPointerException中的异常       在org.at.network.types.CustomE.hashCode(CustomE.java:71)       在java.util.HashMap.hash(HashMap.java:366)       在java.util.HashMap.getEntry(HashMap.java:466)       在java.util.HashMap.containsKey(HashMap.java:453)       at org.jgrapht.graph.Abs​​tractBaseGraph.containsEdge(AbstractBaseGraph.java:359)       在org.jgrapht.graph.Abs​​tractBaseGraph.addEdge(AbstractBaseGraph.java:208)       在org.jgrapht.graph.GraphDelegator.addEdge(GraphDelegator.java:131)       在org.jgrapht.graph.DefaultListenableGraph.addEdge(DefaultListenableGraph.java:162)       在org.at.network.types.MyGraph.addCustomEdge(MyGraph.java:27)       在org.at.network.Test.main(Test.java:220)

addcustomedge方法如下:

public CustomE addCustomEdge(V sourceVertex, Port sourcePort, 
        V targetVertex, Port targetPort){
    CustomE l = (CustomE)super.addEdge(sourceVertex, targetVertex);
    l.setSourceP(sourcePort);
    l.setTargetP(targetPort);

    return l;
}

端口只是几个字符串的简单数据结构。

1 个答案:

答案 0 :(得分:1)

对于初始问题的答案:Overriding equals and hashCode in Java

  

每当a.equals(b),则a.hashCode()必须与b.hashCode()相同

在使用基于散列的数据结构时特别相关,因为元素根据其哈希码放入存储桶中,并且只使用equals()对同一存储桶中的元素进行比较。


myGraph.addEdge(a,b);使用EdgeFactory隐含地创建边缘(可能是ClassBasedEdgeFactory)。查看AbstractBaseGraph中的第206行和后续行,其中异常来自:

E e = edgeFactory.createEdge(sourceVertex, targetVertex);

if (containsEdge(e)) { // this restriction should stay!

正如你自己所说,你使用默认构造函数来构造边缘(顺便说一下,你甚至似乎都没有设置顶点):

CustomE l = (CustomE)super.addEdge(sourceVertex, targetVertex);
l.setSourceP(sourcePort);
l.setTargetP(targetPort); 

这意味着,在containsEdge使用边缘时,它未完全初始化!通常,在将对象暴露给代码之前,您没有绝对控制权,它应该被初始化。您刚刚遇到了暴露未初始化对象时可能出现的许多问题之一。特别是,当null执行基于散列的查找时,源和目标仍为containsEdge,此代码为:

(getSource() == null? 0:getSource().hashCode())

抛出NullPointerException

问题的解决方法是在将边缘传递给JGraphT API之前完全初始化边缘。由于您不仅设置了源和目标顶点,还设置了端口,EdgeFactory.createEdge()似乎没有足够的信息来执行此操作。幸运的是,似乎有一个重载方法Graph.addEdge(V sourceVertex, V targetVertex, E e)。我建议你这样使用它:

public CustomE addCustomEdge(V sourceVertex, Port sourcePort, 
        V targetVertex, Port targetPort){
    CustomE l = new CustomE(sourceVertex, sourcePort, targetVertex, targetPort);
    boolean added = addEdge(sourceVertex, targetVertex, l);
    if(added) return l;
    else return null;
}

当然,您首先必须创建CustomE构造函数。