Равно между двумя графиками не получается... как так?

Я попытался просто приравнять два экземпляра 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;
}

и увидел, что метод containsEdge() дает сбой, если это ребро не является ТОЧНЫМ объектом. Это странно, так как я позаботился о том, чтобы переопределить методы equals как для ребер, так и для переключателей...

редактировать: сделал этот эксперимент:

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(). Теперь это работает для вершин, но для ребер я получаю исключение нулевого указателя в хэш-коде, это мой переопределенный метод:

@Override
public int hashCode() {

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

Я получаю нулевой указатель, когда пытаюсь создать ребро на графике (я полагаю, здесь вызывается hashcode()):

myGraph.addEdge(a,b);

Проблема в том, что getSource() и getTarget() возвращают null при вызове в этот момент... как решить? Это стек исключений:

Исключение в потоке «основной» 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) в org.jgrapht.graph.AbstractBaseGraph.containsEdge(AbstractBaseGraph.java:359) в org.jgrapht.graph.AbstractBaseGraph .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;
}

Порт — это просто простая структура данных для пары строк.


person Phate    schedule 27.05.2014    source источник
comment
пожалуйста, покажите нам свои методы hashCode и equals.   -  person Silly Freak    schedule 27.05.2014
comment
кроме того, у вас есть некоторые другие проблемы: предположим, что this имеет ребра {e1, e2}, а other имеет {e2}. ваш цикл не поймет, что e1 отсутствует в this. проще всего также проверить количество ребер (и вершин).   -  person Silly Freak    schedule 27.05.2014
comment
Методы Equals просто сравнивают пару внутренних атрибутов двух объектов... Я не перезаписывал hashcode()   -  person Phate    schedule 27.05.2014
comment
Глупый урод спасибо за отзыв. В любом случае что-то все равно не работает, так как я пытался сравнить два совершенно одинаковых графика и получил ложный ответ...   -  person Phate    schedule 27.05.2014
comment
Я знаю, я просто хотел указать на это. вы смотрели на javadoc для Object.equals и hashCode? убедитесь, что вы понимаете это, и вы получите свой ответ.   -  person Silly Freak    schedule 27.05.2014
comment
Я знаю, о чем говорю, и не в первый раз переопределяю метод equals...   -  person Phate    schedule 27.05.2014
comment
stackoverflow.com/questions/27581/ Всякий раз, когда a.equals(b), тогда a.hashCode() должно быть таким же, как b.hashCode(), что особенно актуально при использовании HashSet, как вы, вероятно, делаете в edgeSet(). Я тоже знаю, о чем говорю.   -  person Silly Freak    schedule 27.05.2014
comment
Извините, вы были правы :) У меня все еще есть другая проблема (отредактированный вопрос, в любом случае, если вы ответите мне, я отмечу его как правильный)   -  person Phate    schedule 27.05.2014
comment
если вы опубликуете трассировку стека NPE, это будет проще, хотя я почти уверен, в чем проблема   -  person Silly Freak    schedule 28.05.2014
comment
о, и ваш конструктор CustomE тоже важен.   -  person Silly Freak    schedule 28.05.2014


Ответы (1)


Для ответа на начальную проблему: Переопределение equals и hashCode в Java

Всякий раз, когда a.equals(b), a.hashCode() должен быть таким же, как b.hashCode()

это особенно актуально при использовании структур данных на основе хэшей, так как элементы помещаются в сегменты в соответствии с их хэш-кодами, и только те, которые находятся в одном сегменте, сравниваются с использованием equals().


myGraph.addEdge(a,b); неявно создает ребро, используя EdgeFactory (предположительно ClassBasedEdgeFactory). Посмотрите на строки 206 и последующие в AbstractBaseGraph, откуда исходит исключение:

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.

person Silly Freak    schedule 27.05.2014
comment
Спасибо, а как убедиться, что источник и цель установлены? Любые идеи? Я также думаю, что просто заставить hashcode() возвращать константу... будет ли это неправильно? - person Phate; 28.05.2014
comment
Вы показываете слишком мало кода, чтобы так говорить. как я сказал в комментарии к вопросу, мне нужна как минимум трассировка стека вашего исключения с нулевым указателем и конструктор CustomE. - person Silly Freak; 28.05.2014
comment
Конструктор вообще не определен, поэтому он называется конструктором по умолчанию. Я отредактировал основной вопрос, показывающий трассировку стека. - person Phate; 29.05.2014
comment
Тогда я не могу вам помочь. У этого вопроса есть несколько применений для будущих зрителей, касающихся equals и правильной инициализации объектов, но дальнейшее добавление к нему будет медленно ухудшать его до чего-то бесполезного для кого-либо, кроме вас. Я предлагаю вам отладить свой код (поищите в Интернете, как отлаживать java в вашей среде IDE) и убедиться, что вершины вашего CustomE инициализированы до вызова hashCode. - person Silly Freak; 04.06.2014