在 equals 方法中比较两个对象名称

Comparing two objects names in an equals method

我不太了解如何正确比较我正在测试的对象。我的问题是,由于代码的原因,测试本身总是正确的,但我想到的任何其他方式也不能正常工作。

public class Element {

    private String atomLetter;
    private String name;

    public Element(String atomLetter, String name) {
        this.atomLetter = atomLetter.toUpperCase();
        this.name = name.toLowerCase();
    }

    public Element(String atomLetter) {
        this(atomLetter, "");
    }

    public String getAtomLetter() {
        return atomLetter;
    }

    public String getName() {
        return name;
    }

    // TODO: two elements are considered to be equal if they have the same atom letter.
    @Override
    public boolean equals(final Object obj) {



        if (atomLetter == this.atomLetter){

            return true;
        }

        return false;

    }

    @Override
    public String toString() {
        return "Element{" +
                "'" + atomLetter + "'" +
                ", name='" + name + '\'' +
                '}';
    }
}

在这种情况下,结果完全相同,但问题在于 equals 方法。

@Test
public void testSimpleMolecules() {
    // simple carbon
    Molecule m1 = new Molecule("");
    assertTrue(m1.isEmpty());
    assertEquals(0, m1.size());
    m1.add(new Element("C"));
    assertFalse(m1.isEmpty());
    assertEquals(1, m1.size());
    assertEquals(new Element("C"), m1.get(0));
    // simple hydrogen
    Molecule m2 = new Molecule("");
    m2.add(new Element("H"));
    assertFalse(m2.isEmpty());
    assertEquals(1, m2.size());
    assertEquals(new Element("H"), m2.get(0));
    // simple nitrogen
    Molecule m3 = new Molecule("");
    m3.add(new Element("N"));
    assertFalse(m3.isEmpty());
    assertEquals(1, m3.size());
    assertEquals(new Element("N"), m3.get(0));
    // simple oxygen
    Molecule m4 = new Molecule("");
    m4.add(new Element("O"));
    assertFalse(m4.isEmpty());
    assertEquals(1, m4.size());
    assertEquals(new Element("O"), m4.get(0));
}

在您的 equals 方法中,您将此对象的 atomLetter 与其自身进行比较。

if (atomLetter == this.atomLetter){ 

相反,您需要将 obj 参数转换为 Element class 并将其 atomLetterthis.atomLetter

进行比较
Element other = (Element) obj;
return this.atomLettet == other.atomLettet;

当然,您可能希望在实际执行之前测试转换是否可行,并说如果对象 class 不同则对象不相等。还要测试是否为空。 object.Equals() 的 javadoc 解释了所有正确的 equals 方法的要求。

关于 this.atomLetter 与自身的比较, 是正确的。 equals.

还有一些其他问题

比较内容,而不是参考文献

您的代码 … == this.atomLetter 正在比较对象引用(指针),而不是那些 String 对象的文本 内容。换句话说,你问的是这两个变量是否都引用同一个对象,即同一个内存块。

总是比较String content by calling String::equals or String::equalsIgnoreCase

为了实现 equals,您 可以 测试引用是否相同,作为相等性测试的快速第一部分。但仅此还不够。

if ( this == other ) return true;

测试空值

您应该测试 null。如果其他对象引用为null,则没有对象,所以不能相等。

 if ( other == null ) return false;

测试 class

您还可以确保两个对象的 class 匹配。

 if ( other == null || getClass() != other.getClass() ) return false;

演员表

正如另一个答案提到的,您应该投射通过的 Object,已经通过上面显示的 class-匹配测试。

Element element = ( Element ) other;

检查匹配内容

作为最后一个测试,检查匹配内容。

在这种特殊情况下,我怀疑您确实关心大小写匹配。所以我们称 String::equals 而不是 String::equalsIgnoreCase.

return getAtomLetter().equals( element.getAtomLetter() );

示例equals方法

让我们将所有内容整合到一个 equals 实现中。

@Override
public boolean equals ( Object other )
{
    if ( this == other ) return true;
    if ( other == null || getClass() != other.getClass() ) return false;
    Element element = ( Element ) other;
    return getAtomLetter().equals( element.getAtomLetter() );
}

提示:您的 IDE 将为您生成此代码。不需要自己写这个。例如,在 IntelliJ 中,选择:Code > Generate > equals() and hashCode.

在实施 equals

时始终实施 hashCode

正如在 Stack Overflow 上多次讨论的那样,例如 here, when writing an equals method, always write a hashCode 使用相同逻辑的方法。

@Override
public int hashCode ( )
{
    return Objects.hash( getAtomLetter() );
}

示例class

所以我们最终得到 Element class 看起来像这样。

package work.basil.example;

import java.util.Objects;

public class Element
{
    // Member fields
    private String atomLetter, name;

    // Constructor
    public Element ( String atomLetter , String name )
    {
        this.atomLetter = Objects.requireNonNull( atomLetter ).toUpperCase();
        if ( this.atomLetter.isBlank() ) { throw new IllegalArgumentException();}
        this.name = Objects.requireNonNull( name ).toLowerCase();
    }

    // Getters (read-only).
    public String getAtomLetter ( ) {return atomLetter;}

    public String getName ( ) {return name;}

    // `Object` overrides

    @Override
    public boolean equals ( Object other )
    {
        if ( this == other ) return true;
        if ( other == null || getClass() != other.getClass() ) return false;
        Element element = ( Element ) other;
        return getAtomLetter().equals( element.getAtomLetter() );
    }

    @Override
    public int hashCode ( )
    {
        return Objects.hash( getAtomLetter() );
    }

    @Override
    public String toString ( )
    {
        return "Element{ " +
                "atomLetter='" + atomLetter + '\'' +
                " | name='" + name + '\'' +
                " }";
    }
}

您可以通过这种方式实现 equals 方法。但是,您还必须实现 hashCode 以确保正确性。

等于

@Override
public boolean equals(Object obj)
{
   // check the instance of obj
   if (!(obj instanceof Element)) return false;
   
   // check if obj is itself
   if (obj == this) return true;
   
   // cast obj as Element
   Element e = (Element) obj;
   
   // compare fields
   return this.atomLetter.equals(e.atomLetter) &&
   this.name.equals(e.name);
 }

对于哈希码,您可以通过多种方式实现它,但通常这是最快捷、最简单的方式。

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