当前位置: 首页 > 知识库问答 >
问题:

根据树集,两个对象显示为相等,但队列显示为不相等

宗政安歌
2023-03-14

我有以下人物班-

<代码>人。java -

public class Person implements Comparable<Person> {
    private int id;
    private String name;

    Person(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Person: Id = " + id + ", Name = " + name;
    }

    @Override
    public int compareTo(Person person) {
        int myReturn = 0;
        int minLength = 0;
        int i = 0;
        boolean equal = false;
        if (id > person.id) {
            myReturn = 1;
        } else if (id < person.id) {
            myReturn = -1;
        } else {
            if (name.length() > person.name.length()) {
                minLength = person.name.length();
            } else if (name.length() < person.name.length()) {
                minLength = name.length();
            } else {
                equal = true;
                minLength = name.length();
            }
            for (i = 0; i < minLength; i++) {
                if (name.charAt(i) > person.name.charAt(i))  {
                    myReturn = 1;
                    break;
                } else if (name.charAt(i) < person.name.charAt(i)) {
                    myReturn = -1;
                    break;
                } else {
                    continue;
                }
            }
            if (i == minLength) {
                if (equal) {
                    myReturn = 0;
                } else if (name.length() > person.name.length()) {
                    myReturn = 1;
                } else {
                    myReturn = -1;
                }
            }
        }
        return myReturn;
    }
}

现在,我有以下TreeClass实例-

TreeSet<Person> treeSet = new TreeSet<>(List.of(
                new Person(4, "Amrita"),
                new Person(4, "Amrita"),
                new Person(9, "Sunita"),
                new Person(12, "Nisha"),
                new Person(9, "Sunit"),
                new Person(9, "Sunitaa")
        ));

打印时-

Person: Id = 4, Name = Amrita
Person: Id = 9, Name = Sunit
Person: Id = 9, Name = Sunita
Person: Id = 9, Name = Sunitaa
Person: Id = 12, Name = Nisha

很明显,两个人的例子-新人(4,“Amrita”)和新人(4,“Amrita”)是相等的。

现在,我有以下队列代码。由于队列是集合接口的子接口,它实现了集合接口的所有方法。所以-

    Queue<Person> queue3 = new LinkedList<>(List.of(
                new Person(4, "Amrita"),
                new Person(2, "Suhana"),
                new Person(7, "Neha")
        ));
        Person person1 = new Person(4, "Amrita");
        Person person2 = new Person(9, "Sunita");
        System.out.println(queue3.contains(person1));
        System.out.println(queue3.contains(person2));

输出-

    false
    false

因此,它表示队列和对象的元素new Person(4,“Amrita”)是不相等的。

这怎么可能呢?


共有2个答案

鲜于渊
2023-03-14
匿名用户

TreeSet专门使用比较器来确定相等性。任何2个条目,例如comparator.compare(a, b)返回0都被视为相等。equalshashCode都不会被调用

大多数其他集合只使用equals或equals与hashCode的组合来确定这一点。

因此,如果您编写的类的equals、hashCode和compare方法不一致,则可以创建您描述的情况:TreeSet认为它们相等,但HashSet不这样认为。

解决方案是正确地应用各种java的Javadoc中列出的规则。util类:

  • a.等于(b)?然后,无论类型如何,b.equals(a)也必须保持不变

有很多规则。它们很容易理解(几乎是显而易见的),但它们很难正确应用,尤其是如果您涉及java具有类型层次结构的想法。

简单的例子:

ArrayList有一个equals impl,它将检查提供的对象是否是任何类型的列表,如果是,它只是进行逐个elem比较。

这意味着您不能编写一个实现List和添加影响任何排序、句点的属性的相等性的类。

例如,此类:

class ColouredList<T> extends ArrayList<T> {
  private Color color;

  public ColouredList(Color color) {
    this.color = color;
  }

  // and so on
}

无法书写-除非您完全忽略颜色,例如,蓝色列表中的空白被视为等同于红色列表中的空白。因为清空plainarraylist。equals(blueEmptyList)为true,不能为false(因为您不控制ArrayList的equals impl),emptyPlainArrayList也是如此。等于(redEmptyList),因此,blueEmptyList。等于(redEmptyList)也必须为true。

此规则是规则集的逻辑结果,但并不明显,事实上,认为您可以这样做是一个常见的错误。

因此,简单的、几乎显而易见的规则结合在一起,形成了一个比你想象的复杂得多的系统。

你违反了这里的一条规则;考虑到粘贴的内容,这看起来很简单:您向类添加了一个自然的比较顺序,但未能实现hashCode和equals。您必须实现这些方法,才能遵循a.equals(b)和a.compare(b)==0的规则(并且您必须实现hashCode来遵循规则“如果a.equals(b),那么您必须确保a.hashCode()==b.hashCode()”。

我建议使用Lombok项目或IDE的“生成等于和哈希代码”选项。这些方法也可能有点难以正确编写。

柴亦
2023-03-14

您需要重写类Person中的equals方法。请参阅文档。

此外,我还看到实现了可比性(TreeSet使用了可比性来表示相等)。每当您覆盖compareTo()时,强烈建议覆盖等于。

从集合文档:

强烈建议(尽管不是必需的)自然顺序与equals一致。这是因为没有显式比较器的排序集(和排序映射)在与自然排序与等于不一致的元素(或键)一起使用时表现“奇怪”。

长话短说,由于您使用的是TreeSet以及其他集合(列表),因此需要@覆盖所有三个-compareTo、equals和hashCode

PS:每当您重写等于时,请也重写哈希代码。看看这个。

您可以在IDE(Intellij/Eclipse/VsCode等)中自动生成这些方法。E、 g.应该是这样的:

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id == person.id && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }

 类似资料:
  • 问题内容: 似乎以下代码应返回true,但返回false。 这有什么意义? 问题答案: 常规()和严格()相等之间的唯一区别是,严格相等运算符禁用类型转换。由于已经在比较两个相同类型的变量,因此使用的相等运算符的类型无关紧要。 不管您使用常规相等还是严格相等,对象比较仅 在您比较相同的精确对象时得出 。 也就是说,给定,,,但。 两个不同的对象(即使它们都具有零或相同的精确属性)也永远不会相等地进

  • 我面临以下异常:中,当我试图显示一个时,该表单包含以前初始化(并显示)的 谢谢

  • 我创建了的两个实例,如下所示。一个是从创建的,另一个是相同的,但在开头加上了一些附加的数字。使用方法比较它们时,它返回: 我认为添加的数字被丢弃了,并且两者给出了相同的UUID字符串值。为什么会这样?

  • 所以这似乎是一个检索问题。代码如下: 受保护的字符串getStringValueNoNulls(ResultSet rs,String colName){ ...print语句的输出: ????(单位:DB) ??????9999(9999单位为DB) ??(单位:DB) 是我错过了什么,还是司机出了问题?请帮帮忙。 ----------------------------------------

  • 我是一个新手Android和工作在一个电子商务应用程序。我有一个产品的模型类(指定产品名称,价格等)。 我想显示从数组列表到列表视图的产品。但是,如果有相同的产品(具有相同的productId)在数组列表中两次,我希望它显示在列表视图中,只有一行,数量-2(请参见图片)。有人能帮我吗? 下面是listview适配器类: 编辑: 请注意,我不能使用HashSet(用于创建唯一列表)或HashMap(

  • 问题内容: Hashcode()和equals()的概念是 1)如果两个对象根据equal()相等,则在这两个对象中的每一个上调用hashcode方法应产生相同的哈希码。 另一个是 2)如果两个对象根据equal()不相等,则不需要在两个对象中的每一个上调用hashcode方法必须产生不同的值。 我尝试并理解了第一个,这是第一点的代码。 上面的程序为两个不同的对象提供了相同的哈希码。 有人可以用一