Java 为什么这个类的compareTo方法不返回边<;A、 B>;及<;B、 A>;同样的事情?
下面是我的Java 为什么这个类的compareTo方法不返回边<;A、 B>;及<;B、 A>;同样的事情?,java,graph,Java,Graph,下面是我的MovieEdge课程;没有什么特别的,它指向2个作为此边顶点的Actor对象。此外,这是一个未加权的无向图,但我们需要添加一个weight字段,即使它将始终初始化为1,因此可以在compareTo方法中忽略权重 因此,在我的graph类中,我调用了我的方法edgeSet,该方法返回所有边的集合,但它是一个集合,因此它应该只添加唯一边,但取下面的这两条边 Actor a = new Actor("James"); Actor b = new Actor("Dan"); MovieEdg
MovieEdge
课程;没有什么特别的,它指向2个作为此边顶点的Actor
对象。此外,这是一个未加权的无向图,但我们需要添加一个weight
字段,即使它将始终初始化为1,因此可以在compareTo
方法中忽略权重
因此,在我的graph
类中,我调用了我的方法edgeSet
,该方法返回所有边的集合,但它是一个集合,因此它应该只添加唯一边,但取下面的这两条边
Actor a = new Actor("James");
Actor b = new Actor("Dan");
MovieEdge one = new MovieEdge(a, b, 1, "Movie1");
MovieEdge one = new MovieEdge(b, a, 1, "Movie1");
我的compareTo方法在比较上面的两个MovieEdge时应该输出0,因为这是一个无向图,但当我在主方法中调用以下内容时
testGraph.addEdge(A, C, 1, "Movie1");
testGraph.addEdge(B, C, 1, "Movie1");
testGraph.addEdge(C, D, 1, "Movie3");
testGraph.addEdge(D, A, 1, "Movie1");
testGraph.addEdge(A, D, 1, "Movie1");
testGraph.addEdge(A, E, 1, "Movie1");
System.out.println(testGraph.edgeSet());
在我的主要方法中,这是输出
[A通过电影1到C,A通过电影1到D,A通过电影1到E,B通过电影1到C,C通过电影1到A,E通过电影1到A,C通过电影3到D]
请注意集合如何同时显示这两个属性
A通过电影1到E
和E通过电影1到A
这是不对的
我从凌晨2点(现在是早上7:43)开始将“compareTo”更改为,但我不明白,返回0的前两个条件应该解决此问题,但由于某些原因,它不是
我还应该指出,奇怪的是,当我只添加一条边时,比如testGraph.addEdge(a,E,1,“Movie1”)
并调用System.out.println(testGraph.edgeSet())代码>正确打印,并且仅在控制台上打印[A via Movie1 to E]
public class MovieEdge implements Comparable {
private Actor source;
private Actor destination;
private int weight;
private String movieName;
public MovieEdge(Actor source, Actor destination, int wieght, String movieName){
this.source = source;
this.destination = destination;
this.weight = weight;
this.movieName = movieName;
}
public Actor getSource() {
return source;
}
public Actor getDestination() {
return destination;
}
public int getWeight(){
return weight;
}
public String getMovieName() {
return movieName;
}
public String toString(){
return source + " via " + movieName + " to " + destination ;
}
@Override
public int compareTo(Object o) {
MovieEdge a = (MovieEdge)o;
if(this.movieName.equals(a.movieName)){
if(this.source.getName().equals(a.source.getName()) && this.destination.getName().equals(a.destination.getName())){
return 0;
}
else if(this.source.getName().equals(a.destination.getName()) && this.destination.getName().equals(a.source.getName())){
return 0;
}
else if(this.destination.compareTo(a.destination) != 0 || this.source.compareTo(a.source) !=0 ){
return 1;
}
return 0;
}
if(this.movieName.compareTo(a.movieName) < 0){
return -1;
}else if(this.movieName.compareTo(a.movieName) > 0){
return 1;
}
return -1;
}
}
基本上,代码中有两个错误:
首先,您实现了一个Comparable
,但不重写equals()
方法。
从
强烈建议(尽管不是必需的)自然
排列顺序必须与等号一致。这是因为排序集
没有显式比较器的(和排序贴图)在
它们与自然顺序为的元素(或键)一起使用
与平等不一致。特别是这样一个排序集(或排序集)
map)违反了已定义的set(或map)总合同
根据equals方法
第二,如果movieName
相等,但源
和目标
不相等,那么您的可比对象会有一种奇怪的行为,因为它总是返回1
。这打破了:
(x.compareTo(y)>0&&y.compareTo(z)>0)表示x.compareTo(z)>0
这会导致您的TreeSet
无法正常工作,因此您的边缘被添加了两次
Edit:据我所知,与
方法相比,compareTo没有简单的实现。因此,我建议使用带有方便的hashCode
和equals
方法的HashSet
。诸如此类:
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + Objects.hashCode(movieName);
result *= prime;
// Only add, because order independent
result += Objects.hashCode(destination);
result += Objects.hashCode(source);
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MovieEdge other = (MovieEdge)obj;
if (Objects.equals(movieName, other.movieName))
{
if (Objects.equals(source, other.source)
&& Objects.equals(destination, other.destination))
{
return true;
}
if (Objects.equals(source, other.destination)
&& Objects.equals(destination, other.source))
{
return true;
}
}
return false;
}
Lumnitz提供的答案是正确的,我只想补充以下几点:
Set
通过使用equals(Object obj)
方法验证对象的相等性来消除重复,您没有为MovieEdge
类重写该方法
基本上,您需要了解以下几点:
(1) 重写equals()
和hashcode()
(来自java.lang.Object
)以检查对象的相等性(您的情况就是这样,您希望通过使用moviename
等检查某些条件来消除两个MovieEdge
对象)
public boolean equals(Object obj):指示是否有其他对象
等于这个
(2) 重写compareTo(对象o)
(来自java.lang.Comparable
)以对对象进行排序(升序/降序)
可比较的公共接口:此接口强制进行总排序
在实现它的每个类的对象上
@谢谢你的回答。我阅读了Lumnitz链接的类似文档,并获得了一些见解。不管怎样,这对我没有帮助。我继续重写了MovieEdge
的equals
方法,并将我的比较重写为方法,然而,当我打印布景时,仍然会得到重复的。但是,当我比较或使用equals
方法将所有MovieEdge
对象分别与其相等(但翻转的顶点)MovieEdge
对应对象进行比较时,我得到了预期的结果(true和0)。我还可以指出一些让我困惑的问题吗?当我使用LinkedHashSet而不是TreeSet时,会打印出更多的副本!所有集合类是否应使用相同的添加方法以避免重复?如果是这样的话,我觉得奇怪的是他们没有添加相同的内容。@Lumnitz谢谢你,这看起来会起作用,但我没有测试它。不幸的是,我将不得不坚持我的方法,因为我不能使用不是我的代码,但无论如何,谢谢。至少我在个人项目上不会有这个问题,但在学校我只能使用我自己的代码。
`@Override
public int hashCode(){
return source.getName().hashCode() + destination.getName().hashCode();
}
@Override
public boolean equals(Object obj){
MovieEdge a = (MovieEdge)obj;
if((source.getName().equals(a.source.getName())) && (destination.getName().equals(a.destination.getName()))){
return true;
}
if((source.getName().equals(a.destination.getName())) && (destination.getName().equals(a.source.getName()))){
return true;
}
return false;
}
@Override
public int compareTo(Object o) {
MovieEdge a = (MovieEdge)o;
if(movieName.equals(a.movieName)){
if(equals(a))
return 0;
else if(source.getName().compareTo(a.source.getName()) < 0)
return -1;
else
return 1;
}else if(movieName.compareTo(a.movieName) < 0)
return -1;
return 1;
} `
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + Objects.hashCode(movieName);
result *= prime;
// Only add, because order independent
result += Objects.hashCode(destination);
result += Objects.hashCode(source);
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MovieEdge other = (MovieEdge)obj;
if (Objects.equals(movieName, other.movieName))
{
if (Objects.equals(source, other.source)
&& Objects.equals(destination, other.destination))
{
return true;
}
if (Objects.equals(source, other.destination)
&& Objects.equals(destination, other.source))
{
return true;
}
}
return false;
}