2015-02-12 29 views
2

我對Java泛型相對較新,以下兩個泛型類表示Graph數據結構中涉及的頂點和連接器。通過非遞歸函數發生的Stackoverflow異常

Connector.java類

package ac.lk.iit.algorithmscomplexities.coursework2.datastructure; 
public class Connector<E,F> { 
    private Vertex<E, F> start, end; // starting Vertex instance and ending Vertex instance of the Connector 
    private F element; // the data of generic type F to be held by the Vertex connector 
    private double value; // a descriptive value of the connector relative to other connectors depending on the scenario 

    /** 
    * a protected constructor which creates an instance of Connector class 
    * @param start starting Vertex instance of the Connector 
    * @param end ending Vertex instance of the Connector 
    * @param element data of generic type F to be held by the Vertex connector 
    * @param cost descriptive value of the connector relative to other connectors depending on the scenario 
    */ 
    protected Connector(Vertex<E,F> start, Vertex<E,F> end, F element, double cost) { 
     this.setStart(start); 
     this.setEnd(end); 
     this.setElement(element); 
     this.setValue(cost); 
    } 

    /** 
    * returns the starting Vertex instance of the Connector 
    * @return the starting Vertex instance of the Connector 
    */ 
    protected Vertex<E,F> getStart() { 
     return start; 
    } 

    /** 
    * sets the Vertex argument provided to the starting Vertex instance field of the Connector instance 
    * @param start the starting Vertex instance of the Connector 
    */ 
    private void setStart(Vertex<E,F> start) { 
     if(start != null) { 
      this.start = start; 
     } 
    } 

    /** 
    * returns the ending Vertex instance of the Connector 
    * @return the ending Vertex instance of the Connector 
    */ 
    protected Vertex<E,F> getEnd() { 
     return end; 
    } 

    /** 
    * sets the Vertex argument provided to the ending Vertex instance field of the Connector instance 
    * @param end the ending Vertex instance of the Connector 
    */ 
    private void setEnd(Vertex<E,F> end) { 
     if(end != null) { 
      this.end = end; 
     } 
    } 

    /** 
    * returns the data of generic type F held by the Vertex connector 
    * @return the data of generic type F held by the Vertex connector 
    */ 
    protected F getElement() { 
     return element; 
    } 

    /** 
    * sets the data of generic type F to the element instance field of the Vertex connector 
    * @param element data of generic type F to be held by the Vertex connector 
    */ 
    private void setElement(F element) { 
     if(element != null) { 
      this.element = element; 
     } 
    } 

    /** 
    * returns a descriptive value of the connector relative to other connectors depending on the scenario 
    * @return descriptive value of the connector relative to other connectors depending on the scenario 
    */ 
    protected double getValue() { 
     return value; 
    } 

    /** 
    * sets a descriptive value of the connector relative to other connectors depending on the scenario to value instance field of Connector instance 
    * @param value a descriptive value of the connector relative to other connectors depending on the scenario 
    */ 
    private void setValue(double value) { 
     if(value >= 0) { 
      this.value = value; 
     } 
    } 

    public String toString() { 
     return this.element.toString(); 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public boolean equals(Object object) { 
     if(object instanceof Connector) { 
      Connector<E,F> newConnector = (Connector<E, F>)object; 
      // since it is a directed graph the start, end of each connector and the data element should be unique 
      return ((this.getStart().equals(newConnector.getStart())) && (this.getEnd().equals(newConnector.getEnd())) && (this.getElement().equals(newConnector.getElement()))); 
     } 
     else { 
      return false; 
     } 
    } 
} 

Vertex.java類

package ac.lk.iit.algorithmscomplexities.coursework2.datastructure; 
import java.util.LinkedList; 
public class Vertex<E,F> { 

    private int id;   // a unique id value for each vertex created 
    private E dataElement; // data to be held within a vertex 
    private LinkedList<Connector<E, F>> pointers; // list of references to other Vertices connected 

    // keeps track of the number of vertices created during the runtime 
    protected static int NUMBER_OF_VERTICES = 0; 

    /** 
    * a protected constructor which creates an instance of Vertex class with the generic E argument provided 
    * @param element the element of generic type E to be assigned to dataElement instance field 
    */ 
    protected Vertex(E element) { 
     this.setId(Vertex.NUMBER_OF_VERTICES); 
     Vertex.NUMBER_OF_VERTICES++; 
     this.setDataElement(element); 
     this.pointers = new LinkedList<Connector<E, F>>(); 
    } 

    /** 
    * returns the unique Integer id value of the Vertex instance 
    * @return the unique Integer id value of the Vertex instance 
    */ 
    protected int getId() { 
     return id; 
    } 

    /** 
    * sets the Integer argument provided to the id instance field of the Vertex instance 
    * @param id the Integer argument provided to be set to the id instance field of the Vertex instance 
    */ 
    private void setId(int id) { 
     if(!(id < 0)) { 
      this.id = id; 
     } 
    } 

    /** 
    * returns the content of the dataElement instance field of the Vertex instance 
    * @return the content of the dataElement instance field of the Vertex instance 
    */ 
    protected E getDataElement() { 
     return dataElement; 
    } 

    /** 
    * sets the argument of generic type E to the dataElement instance field of the Vertex instance 
    * @param dataElement the element of generic type E to be assigned to dataElement instance field 
    */ 
    protected void setDataElement(E dataElement) { 
     if(dataElement != null) { 
      this.dataElement = dataElement; 
     } 
    } 

    /** 
    * returns the list of Connector instances associated with a Vertex instance 
    * @return the list of Connector instances associated with a Vertex instance 
    */ 
    protected LinkedList<Connector<E, F>> getPointers() { 
     return pointers; 
    } 

    /** 
    * adds a new Connector instance starting from this Vertex and ending in the specified Vertex instance 
    * @param another the ending Vertex of the Connector 
    * @param element the data element of generic type F held by the Connector 
    * @param value the list of Connector instances associated with a Vertex instance 
    */ 
    protected void connectTo(Vertex<E,F> another, F element, double value) { 
     Connector<E,F> newConnector = new Connector<E,F>(this, another, element, value); 

     if(!(this.pointers.contains(newConnector))) { 
      this.pointers.add(newConnector); 
     } 

     LinkedList<Connector<E, F>> anotherList = another.getPointers(); 
     if(!(anotherList.contains(newConnector))) { 
      anotherList.add(newConnector); 
     } 

     System.out.println("[this vertex]:" + this.pointers); 
     System.out.println("[that vertex]:" + another.pointers); 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public boolean equals(Object object) { 

     if(object instanceof Vertex) { 
      Vertex<E,F> newVertex = (Vertex<E,F>) object; 
      if(this.pointers.size() != newVertex.getPointers().size()) { 
       return false; 
      } 
      if(!(this.getDataElement().equals(newVertex.getDataElement()))) { 
       return false; 
      } 
      for(int i = 0 ; i < this.pointers.size() ; i++) { 
       if(!(this.pointers.get(i).equals(newVertex.getPointers().get(i)))) { 
        return false; 
       } 
      } 
     } 
     else { 
      return false; 
     } 
     return true; 

    } 

    public static void main(String[] args) { 
     Vertex<String, String> vertex1 = new Vertex<String, String>("Chiranga"); 
     Vertex<String, String> vertex2 = new Vertex<String, String>("Robin"); 
     Vertex<String, String> vertex3 = new Vertex<String, String>("Sunethra"); 
     Vertex<String, String> vertex4 = new Vertex<String, String>("Ananda"); 

     vertex1.connectTo(vertex2, "John", 0); 
     //vertex1.connectTo(vertex3, "Mark", 0); 

     //vertex1.connectTo(vertex4, "Rob", 0); 

     vertex2.connectTo(vertex3, "James", 0); 

     vertex4.connectTo(vertex2, "John", 0); 
     vertex4.connectTo(vertex3, "Sean", 0); 

     //System.out.println(vertex1.equals(vertex4)); 
     //System.out.println(vertex1.equals(vertex2)); 
    } 
} 

上述類執行下面的代碼段時發出一個stackoverflowexception。

vertex4.connectTo(vertex3, "Sean", 0); 

這幾乎是不可能理解,因爲我沒有涉及到任何遞歸代碼示例上述異常背後的真正原因,並因爲它時,我只作一定的頂點實例之間的連接發生。與上述異常類型相關的大多數代碼問題都涉及遞歸,但上面的代碼似乎有所不同。

爲什麼我總是得到提到的stackoverflow異常?

請注意,上述涉及main方法的代碼示例是爲測試目的而編碼的。

+0

小心分享實際的堆棧跟蹤?瘋狂的猜測:這是'equals'方法。 – 2015-02-12 09:11:54

回答

0

equals方法Vertex類別包含:

if(!(this.pointers.get(i).equals(newVertex.getPointers().get(i)))) 

其中this.pointers.get(i)Connector,所以equalsVertex調用equalsConnector

Connector類的equals包含:

return ((this.getStart().equals(newConnector.getStart())) && (this.getEnd().equals(newConnector.getEnd())) && (this.getElement().equals(newConnector.getElement()))); 

而且,由於getStart()getEnd()Vertex型的,這意味着Connectorequals呼籲的Vertexequals

因此撥打VertexConnectorequals可能會導致無限遞歸。

2

看着堆棧跟蹤,可以很容易地理解問題的所在:

Exception in thread "main" java.lang.StackOverflowError 
    at ac.lk.iit.algorithmscomplexities.coursework2.datastructure.Connector.equals(Connector.java:123) 
    at ac.lk.iit.algorithmscomplexities.coursework2.datastructure.Vertex.equals(Vertex.java:117) 
    at ac.lk.iit.algorithmscomplexities.coursework2.datastructure.Connector.equals(Connector.java:123) 
    at ac.lk.iit.algorithmscomplexities.coursework2.datastructure.Vertex.equals(Vertex.java:117) 
    at ac.lk.iit.algorithmscomplexities.coursework2.datastructure.Connector.equals(Connector.java:123) 
    ... 

Connectorequals方法調用Vertexequals方法,它調用Connectorequals方法,...

4

你的equals方法...

當你做對包含方法connectTo它調用等於上的連接器,以確定連接器是否在列表與否。

的用於連接器equals方法:

@SuppressWarnings("unchecked") 
@Override 
public boolean equals(Object object) { 
    if (object instanceof Connector) { 
     Connector<E, F> newConnector = (Connector<E, F>) object; 
     // since it is a directed graph the start, end of each connector and the data element should be unique 
     return ((this.getStart().equals(newConnector.getStart())) && (this.getEnd().equals(newConnector.getEnd())) && (this.getElement().equals(newConnector.getElement()))); 
    } else { 
     return false; 
    } 
} 

注意它是如何做等於在getStart()對比 - 這是一個頂點。然後頂點等於:

@SuppressWarnings("unchecked") 
@Override 
public boolean equals(Object object) { 

    if (object instanceof Vertex) { 
     Vertex<E, F> newVertex = (Vertex<E, F>) object; 
     if (this.pointers.size() != newVertex.getPointers().size()) { 
      return false; 
     } 
     if (!(this.getDataElement().equals(newVertex.getDataElement()))) { 
      return false; 
     } 
     for (int i = 0; i < this.pointers.size(); i++) { 
      if (!(this.pointers.get(i).equals(newVertex.getPointers().get(i)))) { 
       return false; 
      } 
     } 
    } else { 
     return false; 
    } 
    return true; 

} 

因此頂點等於:調用等於this.pointers(連接器)。

換句話說,你的equals方法有一個循環依賴 - 它們每個調用另一個equals方法,因此你會得到一個堆棧溢出異常。