覆盖equals方法和hashCode方法看似简单,但其实不然,如果没有按照jdk的通用规范去覆盖,那么基于这些约定的类将可能无法正常工作,例如基于散列的集合类HashMap和HashSet.
对于值类,我们通常需要覆盖Object.equals方法,因为我们希望通过equals方法知道它们在逻辑上是否相等.相应的这个类的实例可以被用作map的key,或者set的元素的时候才会表现出预期的行为. 对于"值类",枚举是个例外,因为枚举的每个值都是个单例.
在覆盖equals时,必须遵守JavaSE Object的规范:自反性(reflective), 对称性 (symmetric),传递性(transitive),一致性(consistent),对于任何非null的引用x, x.equals(null)返回false. 对于每个覆盖类equals的类,都应该有相应的单元测试去检查是否有没有违反上述约定。下面是个简单的例子:
public class PhoneNumber {
private int countryCode;
private String nationalNumber;
public PhoneNumber(){
super();
}
public PhoneNumber(int countryCode, String nationalNumber) {
super();
this.countryCode = countryCode;
this.nationalNumber = nationalNumber;
}
/**
* @return the countryCode
*/
public int getCountryCode() {
return countryCode;
}
/**
* @param countryCode the countryCode to set
*/
public void setCountryCode(int countryCode) {
this.countryCode = countryCode;
}
/**
* @return the nationalNumber
*/
public String getNationalNumber() {
return nationalNumber;
}
/**
* @param nationalNumber the nationalNumber to set
*/
public void setNationalNumber(String nationalNumber) {
this.nationalNumber = nationalNumber;
}
@Override
public boolean equals(Object o){
if(this == o){
return true;
}
if(!(o instanceof PhoneNumber)){
return false;
}
PhoneNumber pn = (PhoneNumber) o;
return this.countryCode == pn.getCountryCode()
&& ( this.nationalNumber == null ? pn.nationalNumber == null : this.nationalNumber.equals(pn.nationalNumber));
}
}
import static org.junit.Assert.*;
import org.junit.Test;
public class PhoneNumberTest {
@Test
public void testEqualsReflexive(){
PhoneNumber pn1 = new PhoneNumber(86, "12345");
assertTrue(pn1.equals(pn1));
PhoneNumber pn2 = new PhoneNumber();
assertTrue(pn2.equals(pn2));
}
@Test
public void testEqualsSymmetric(){
PhoneNumber pn1 = new PhoneNumber(86, "12345");
PhoneNumber pn2 = new PhoneNumber(86, "12345");
assertEquals(pn1.equals(pn2), pn2.equals(pn1));
}
@Test
public void testEqualsTransitive(){
PhoneNumber pn1 = new PhoneNumber(86, "12345");
PhoneNumber pn2 = new PhoneNumber(86, "12345");
PhoneNumber pn3 = new PhoneNumber(86, new String("12345"));
assertTrue(pn1.equals(pn2));
assertTrue(pn2.equals(pn3));
assertTrue(pn1.equals(pn3));
}
@Test
public void testEqualsConsistent(){
PhoneNumber pn1 = new PhoneNumber(86, "12345");
PhoneNumber pn2 = new PhoneNumber(86, "12345");
for(int i=0; i<10 ; i++){
assertTrue(pn1.equals(pn2));
}
}
@Test
public void testEqualsWithNull(){
PhoneNumber pn1 = new PhoneNumber(86, "12345");
assertFalse(pn1.equals(null));
}
}
当然还有一些实现高质量equals方法的诀窍:
1. 使用==操作符检查"参数是否为正确的引用"
2. 使用instanceof检查类型
3. 把参数转化为正确的类型
4. 选择逻辑比较的关键域,注意比较的顺序,primitive的比较可以放在前面,或者最有可能不一致性的域
5. 如果有double,float类型,用Double.compare,Float.compare比较
6. 覆盖equals重要覆盖hashCode
分享到:
相关推荐
重写equals方法需要遵守通用约定,hashCode方法的实现需要保证equals相同的两个对象的hashCode结果一致。ArrayList、Vector和LinkedList是Java中三种常见的容器集合,每种集合都有其特点和应用场景。
此外,Object 类的设计是为了扩展,它提供了一些非 final 方法,如 equals、hashCode、toString、clone 和 finalize,这些方法都有通用的约定,需要在子类中被覆盖(override)。如果不遵守这些约定,依赖这些约定的...
在重写 equals() 方法时,需要遵守通用约定,包括: 1. 自反性:对于任意的引用值 x,x.equals(x) 一定为 true。 2. 对称性:对于任意的引用值 x 和 y,当 x.equals(y) 返回 true 时,y.equals(x) 也一定返回 true...
在Java编程语言中,`equals()`方法和`==`运算符是两个经常用来比较对象的...同时,为了确保其他自定义类的`equals()`方法正确实现,应遵循通用约定,即同时重写`equals()`和`hashCode()`方法,以保持一致性和正确性。
在Java编程中,`equals`方法是用于比较两个对象是否相等的重要方法。...遵循通用约定和同时更新`hashCode`方法能确保一致性和正确性。通过理解和实践这些原则,开发者可以创建出更可靠、更具可维护性的Java应用程序。
遵循 `equals()` 方法的通用约定可以帮助开发人员编写出更加健壮和易于维护的代码。此外,理解何时以及如何重写 `equals()` 方法对于创建高质量的Java应用程序至关重要。通过遵循上述指导原则,可以确保在实际应用中...
- **项03:覆盖equals时请遵守通用约定**:正确的equals方法实现对于确保对象一致性至关重要。 #### 代码设计原则 - **项04:始终覆盖hashCode**:当重写了equals方法时,必须同时重写hashCode方法以保持一致性。 ...
10. **R10:同时定义equals()和hashCode()方法** - 如果重写了`equals()`方法,则也应该重写`hashCode()`方法。 - 这样可以确保当两个对象相等时,它们具有相同的哈希码。 11. **R11:添加新字段时重新定义equals...
根据给定的文件信息,以下是对“core java...Object是所有Java类的根类,提供了如toString()、equals()、hashCode()等基础方法,用于支持对象的基本操作。理解并适当重写这些方法对于编写高质量的Java代码至关重要。
2. **基本方法实现**:为通用目的创建的类,应包含`equals()`、`hashCode()`、`toString()`、`clone()`(实现`Cloneable`)和`Serializable`接口,以提供标准的行为。 3. **测试代码**:每个类都应该有一个`main()`...
**Java中的Object类**:在Java中,所有类都直接或间接地继承自Object类,它提供了所有Java对象通用的行为,如toString()、equals()和hashCode()等方法。通过继承,我们可以为特定类添加额外的功能,同时保持与Java...
集合处理部分提供了处理集合时的建议,如避免null元素、正确使用equals()和hashCode()等。并发处理部分讲述了多线程编程中的最佳实践,包括锁的使用、线程安全的变量等。控制语句的规约指导如何有效使用if、for、...
变量和方法名使用小驼峰命名法,如`myVariableName`;常量全大写,单词间用下划线分隔,如`MY_CONSTANT`。 2. **注释**:良好的注释能够帮助他人理解代码。类注释通常描述类的功能和用途,方法注释解释方法的作用和...
- 重写`equals()`和`hashCode()`方法时,确保满足对象相等性的约定。 - 尽可能使用接口而非具体类进行类型声明,提高代码的灵活性。 【开发EJB规则】 - 遵守Enterprise JavaBeans(EJB)的官方规范,如实体Bean、...
2. **基础方法**:为通用类提供`equals()`、`hashCode()`、`toString()`、`clone()`(实现`Cloneable`)和`Serializable`接口,以支持基本操作和序列化。 3. **测试代码**:为每个自定义类创建一个`main()`方法,...
- 创建通用类时,应包含常用的方法:`equals()`、`hashCode()`、`toString()`、`clone()`(实现`Cloneable`)和`Serializable`接口。 3. **测试代码**: - 为每个类提供一个`main()`方法用于测试,方便检查和验证...
2. **常规类设计**:创建通用类时,包括`equals()`、`hashCode()`、`toString()`、`clone()`(实现`Cloneable`)和`Serializable`接口。这些方法提供了基本的对象操作和比较。 3. **测试代码**:每个类都应该有一个...
为了确保对象的正确比较和操作,应实现`equals()`, `hashCode()`, `toString()`等方法。如果类实现了`Cloneable`接口,还需提供`clone()`方法;若要序列化对象,则需实现`Serializable`接口。这些方法的正确实现对于...