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;
}