java对象equals方法的重写

根类Object中的equals方法描述:

public boolean equals(Object obj)
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returnstrue if and only if x and y refer to the same object (x == y has the value true).
String类重写了equals方法:
public boolean equals(Object anObject)
Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object
1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean
  他们之间的比较,应用双等号(==),比较的是他们的值。
2.复合数据类型(类)
  当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false。 JAVA当中所有的类都是继承于Object这个基类的,在Object中的基类中定义了一个equals的方法,这个方法的初始行为是比较对象的内存地址(即引用里的内容),但在一些类库当中这个方法被覆盖掉了,如String,Integer,Date在这些类当中equals有其自身的实现,而不再是比较类在堆内存中的存放地址了。
  对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是基于他们在内存中的存放位置的地址值的,因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。
1.何时需要重写equals()
当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念)。
2.设计equals()
[1]使用instanceof操作符检查“实参是否为正确的类型”。
[2]对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值。
[2.1]对于非float和double类型的原语类型域,使用==比较;
[2.2]对于对象引用域,递归调用equals方法;
[2.3]对于float域,使用Float.floatToIntBits(afloat)转换为int,再使用==比较;
[2.4]对于double域,使用Double.doubleToLongBits(adouble) 转换为int,再使用==比较;
[2.5]对于数组域,调用Arrays.equals方法。
public boolean equals(Object obj)
{
    if(obj == null)    return false; //keep the object compared not be null
    else{
        if(obj instanceof Cat)   //keep the object input be Cat
        {
            Cat c = (Cat) obj;    //Cast to Cat
            if(c.color == this.color&& c.height == this.hright)
            {
                   return true;
            }
        }
       }

    return false;
}

 

3.当改写equals()的时候,总是要改写hashCode()
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”。
4.设计hashCode()
[1]把某个非零常数值,例如17,保存在int变量result中;
[2]对于对象中每一个关键域f(指equals方法中考虑的每一个域):
[2.1]boolean型,计算(f ? 0 : 1);
[2.2]byte,char,short型,计算(int);
[2.3]long型,计算(int) (f ^ (f>>>32));
[2.4]float型,计算Float.floatToIntBits(afloat);
[2.5]double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];
[2.6]对象引用,递归调用它的hashCode方法;
[2.7]数组域,对其中每个元素调用它的hashCode方法。
[3]将上面计算得到的散列码保存到int变量c,然后执行 result=37*result+c;
[4]返回result。
5.示例
下面的这个类遵循上面的设计原则,重写了类的equals()和hashCode()。
 1 package com.zj.unit;
 2 import java.util.Arrays;
 3  
 4 public class Unit {
 5     private short ashort;
 6     private char achar;
 7     private byte abyte;
 8     private boolean abool;
 9     private long along;
10     private float afloat;
11     private double adouble;
12     private Unit aObject;
13     private int[] ints;
14     private Unit[] units;
15  
16     public boolean equals(Object o) {
17        if (!(o instanceof Unit))
18            return false;
19        Unit unit = (Unit) o;
20        return unit.ashort == ashort
21               && unit.achar == achar
22               && unit.abyte == abyte
23               && unit.abool == abool
24               && unit.along == along
25               && Float.floatToIntBits(unit.afloat) == Float
26                      .floatToIntBits(afloat)
27               && Double.doubleToLongBits(unit.adouble) == Double
28                      .doubleToLongBits(adouble)
29               && unit.aObject.equals(aObject)
30 && equalsInts(unit.ints)
31               && equalsUnits(unit.units);
32     }
33  
34     private boolean equalsInts(int[] aints) {
35        return Arrays.equals(ints, aints);
36     }
37  
38     private boolean equalsUnits(Unit[] aUnits) {
39        return Arrays.equals(units, aUnits);
40     }
41  
42     public int hashCode() {
43        int result = 17;
44        result = 37 * result + (int) ashort;
45        result = 37 * result + (int) achar;
46        result = 37 * result + (int) abyte;
47        result = 37 * result + (abool ? 0 : 1);
48        result = 37 * result + (int) (along ^ (along >>> 32));
49        result = 37 * result + Float.floatToIntBits(afloat);
50        long tolong = Double.doubleToLongBits(adouble);
51        result = 37 * result + (int) (tolong ^ (tolong >>> 32));
52        result = 37 * result + aObject.hashCode();
53        result = 37 * result + intsHashCode(ints);
54        result = 37 * result + unitsHashCode(units);
55        return result;
56     }
57  
58     private int intsHashCode(int[] aints) {
59        int result = 17;
60        for (int i = 0; i < aints.length; i++)
61            result = 37 * result + aints[i];
62        return result;
63     }
64  
65     private int unitsHashCode(Unit[] aUnits) {
66        int result = 17;
67        for (int i = 0; i < aUnits.length; i++)
68            result = 37 * result + aUnits[i].hashCode();
69        return result;
70     }
71 }
View Code
关键是如何计算hashcode值.
此外要注意如何在Java中避免equals方法的隐藏陷阱(http://coolshell.cn/articles/1051.html)
下面给出比较成熟的equals()代码:
 1 public boolean equals(Object obj)
 2 {
 3     if(this == obj)
 4     {
 5         return true;
 6     }
 7     if(obj != null && obj.getClass() == Person.class)
 8     {
 9         Person personObj = (Person) obj;
10         if(this.getldStr().equals(personObj.getldStr()))
11         {
12             return true;
13         }
14     }
15 
16     return false;
17 }

 忠告:1、覆盖equals时总要覆盖hashcode; 2、Don’t try to be too clever不要试图让equals方法过于智能; 3、Don’t substitute another type for Object in the equals declaration.不要将equals声明中Object对象替换为其他对象

public boolean equals(MyClass o) {
...
}需使用Object o

附转载:http://www.importnew.com/8701.html 或 http://www.programcreek.com/2011/07/java-equals-and-hashcode-contract/

java-hashcode


The Java super class java.lang.Object has two very important methods defined:


public boolean equals(Object obj)
public int hashCode()

They have been proved to be extremely important to understand, especially when user-defined objects are added to Maps. However, even advanced-level developers sometimes can’t figure out how they should be used properly. In this post, I will first show an example of a common mistake, and then explain how equals() and hashCode contract works.


1. A common mistake


Common mistake is shown in the example below.


import java.util.HashMap;
 
public class Apple {
	private String color;
 
	public Apple(String color) {
		this.color = color;
	}
 
	public boolean equals(Object obj) {
		if (!(obj instanceof Apple))
			return false;	
		if (obj == this)
			return true;
		return this.color.equals(((Apple) obj).color);
	}
 
	public static void main(String[] args) {
		Apple a1 = new Apple("green");
		Apple a2 = new Apple("red");
 
		//hashMap stores apple type and its quantity
		HashMap<Apple, Integer> m = new HashMap<Apple, Integer>();
		m.put(a1, 10);
		m.put(a2, 20);
		System.out.println(m.get(new Apple("green")));
	}
}

In this example, a green apple object is stored successfully in a hashMap, but when the map is asked to retrieve this object, the apple object is not found. The program above prints null. However, we can be sure that the object is stored in the hashMap by inspecting in the debugger:



2. Problem caused by hashCode()


The problem is caused by the un-overridden method “hashCode()”. The contract between equals() and hasCode() is that:
1. If two objects are equal, then they must have the same hash code.
2. If two objects have the same hashcode, they may or may not be equal.


The idea behind a Map is to be able to find an object faster than a linear search. Using hashed keys to locate objects is a two-step process. Internally the Map stores objects as an array of arrays. The index for the first array is the hashcode() value of the key. This locates the second array which is searched linearly by using equals() to determine if the object is found.


The default implementation of hashCode() in Object class returns distinct integers for different objects. Therefore, in the example above, different objects(even with same type) have different hashCode.


Hash Code is like a sequence of garages for storage, different stuff can be stored in different garages. It is more efficient if you organize stuff to different place instead of the same garage. So it’s a good practice to equally distribute the hashCode value. (Not the main point here though)


The solution is to add hashCode method to the class. Here I just use the color string’s length for demonstration.


public int hashCode(){
	return this.color.length();	
}


posted @ 2013-07-06 17:49  CoolRandy  阅读(730)  评论(0编辑  收藏  举报