java equals 原则与违反
Object 中equals的约定指出 equals 必须实现非空对象的等值关系:
◆自反性:对于如何非空值 x,表达式 x.equals(x) 应返回true。
◆对称性:对于任何非空值:x 和 y,x.equals(y) 应返回true,当且仅当 y.equals(x) 返回 true。
◆传递性:对于任何非空值 x、y、z,如果 x.equals(y)返回 true 并且 y.equals(z) 返回 true,那么x.equals(z) 应返回 true。
◆一致性:对于任何非空值:x 和 y,如果对象的equals比较中所用信息未被修改,多次调用 x.equals(y)应始终返回 true 或始终返回 false。
◆对于任何非空值 x,x.equals(null) 应返回 false。
违反示例:
自反性,较容易避免,一般是equals 方法逻辑有明显问题:
public class Bo { private String id; public Bo(){ } public Bo(String id){ this.id = id; } public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public boolean equals(final Object other) { return false; } @Override public int hashCode() { return new HashCodeBuilder().append(id).toHashCode(); } public static void main(String[] args) { Bo b = new Bo(); System.out.println(b.equals(b));// return false } }对称性,这是人们常会换的错误:
//重写上例Bo equals 方法 @Override public boolean equals(final Object other) { if (!(other instanceof Bo)) return false; Bo castOther = (Bo) other; return new EqualsBuilder().append(id, castOther.id).isEquals(); } //增加子类C public class Co extends Bo { public Co(){ } public Co(String id,String name){ super(id); this.name = name; } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(final Object other) { if (!(other instanceof Co)) return false; Co castOther = (Co) other; return new EqualsBuilder().append(name, castOther.name).isEquals() && super.equals(other); } public static void main(String[] args) { Bo b = new Bo("1"); Co c1 = new Co("1","center"); System.out.println(b.equals(c1)); // true System.out.println(c1.equals(b));// false } }
传递性,这也是常遇到的:
public class Co extends Bo { public Co(){ } public Co(String id,String name){ super(id); this.name = name; } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(final Object other) { boolean result = false; if (other instanceof Co) { Co that = (Co) other; result = (this.name.equals(that.name) && super.equals(that)); }else if (other instanceof Bo) { Bo that = (Bo) other; result = that.equals(this); } return result; } public static void main(String[] args) { Bo b = new Bo("1"); Co c1 = new Co("1","au"); Co c2 = new Co("1","bu"); System.out.println(b.equals(c1)); System.out.println(c1.equals(b)); System.out.println(c2.equals(b)); System.out.println(c1.equals(c2)); //违反传递性 } }后两种特性违反情况较少,可自举例。
另外还需要注意的:
1. equals 方法是 Override ,而不能重载
2. 对象域是非final 时,注意存储在set 中后更改域值后 调用contains 返回错误。