我对如何正确比较正在测试的对象有些困惑。我的问题是,由于代码的原因,测试本身总是正确的,但是我想到的任何其他方式也都无法正常工作。
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));
}
答案 0 :(得分:3)
在equals方法中,您正在将该对象的atomLetter
与自身进行比较。
if (atomLetter == this.atomLetter){
相反,您需要将obj
参数转换为Element
类,并将其atomLetter
与this.atomLetter
Element other = (Element) obj;
return this.atomLettet == other.atomLettet;
当然,您可能需要在实际进行转换之前测试其是否可以转换,并说如果对象属于不同的类,则它们是不相等的。同时测试是否为空。 object.Equals()的Javadoc解释了所有对适当equals方法的要求。
答案 1 :(得分:2)
关于您将this.atomLetter
与自身进行比较,Answer by DarkSigma是正确的。 equals
还有其他一些问题。
您的代码… == this.atomLetter
正在比较对象引用(指针),而不是那些String
对象的文本 content 。换句话说,您要问两个变量是否都指向同一个对象,即相同的内存块。
始终通过调用String
或String::equals
比较String::equalsIgnoreCase
的内容。
要实现equals
,您可以 测试引用是否相同,这是等同测试的快速第一部分。但这还不够。
if ( this == other ) return true;
您应该测试null
。如果另一个对象引用为null,则没有对象,因此不会存在相等性。
if ( other == null ) return false;
您还可以确保两个对象的类匹配。
if ( other == null || getClass() != other.getClass() ) return false;
正如提到的其他答案一样,您应该在通过以上所示的类匹配测试之后,对通过的Object
进行转换。
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
。
hashCode
时始终实施equals
正如在堆栈溢出问题上多次讨论的,例如here,在编写equals
方法时,请始终使用相同的逻辑来编写hashCode
方法。
@Override
public int hashCode ( )
{
return Objects.hash( getAtomLetter() );
}
所以我们最终得到了一个Element
类,看起来像这样。
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 + '\'' +
" }";
}
}
答案 2 :(得分:0)
您可以通过这种方式实现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);
}