我对Java Generics相对较新,以下两个Generic类表示Graph数据结构中涉及的Vertex和Connector。
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);
几乎不可能理解上述异常背后的真正原因,因为我没有涉及任何递归代码示例,并且因为它仅在我在某些Vertex实例之间建立连接时发生。与上述异常类型相关的大多数代码问题都是关于递归的,但上面的代码似乎有所不同。
为什么我总是得到提到的stackoverflow异常?
请注意,上述涉及主要方法的代码示例已编码用于测试目的。
答案 0 :(得分:4)
你的平等方法......
在connectTo中执行contains方法时,它会在连接器上调用equals以确定连接器是否在列表中。
连接器的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()的比较 - 这是一个顶点。然后Vertex等于:
@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;
}
所以Vertex Equals:在this.pointers(Connectors)上调用equals。
所以换句话说,你的equals方法有一个循环依赖 - 它们每个都调用另一个equals方法,因此你得到一个堆栈溢出异常。
答案 1 :(得分: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)
...
您的Connector
equals
方法调用Vertex
equals
方法,该方法调用Connector
的{{1}}方法,...
答案 2 :(得分:0)
equals
类的 Vertex
方法包含:
if(!(this.pointers.get(i).equals(newVertex.getPointers().get(i))))
其中this.pointers.get(i)
是Connector
,equals
Vertex
equals
来自Connector
。
equals
类的 Connector
包含:
return ((this.getStart().equals(newConnector.getStart())) && (this.getEnd().equals(newConnector.getEnd())) && (this.getElement().equals(newConnector.getElement())));
由于getStart()
和getEnd()
的类型为Vertex
,这意味着equals
的{{1}}正在调用Connector
equals
}。
因此,调用Vertex
或equals
的{{1}}可能会导致无限递归。