天天看點

JAVA重新對象equals方法_java對象equals方法的重寫

根類Object中的equals方法描述:

public boolean equals(Object obj)

Theequalsmethod for classObjectimplements the most discriminating possible equivalence relation on objects; that is, for any non-null reference valuesxandy, 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 istrueif and only if the argument is notnulland is aStringobject 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 booleanequals(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 thehashCodemethod whenever this method is overridden, so as to maintain the general contract for thehashCodemethod, 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()。

JAVA重新對象equals方法_java對象equals方法的重寫
JAVA重新對象equals方法_java對象equals方法的重寫

1 packagecom.zj.unit;2 importjava.util.Arrays;3

4 public classUnit {5 private shortashort;6 private charachar;7 private byteabyte;8 private booleanabool;9 private longalong;10 private floatafloat;11 private doubleadouble;12 privateUnit aObject;13 private int[] ints;14 privateUnit[] units;15

16 public booleanequals(Object o) {17 if (!(o instanceofUnit))18 return false;19 Unit unit =(Unit) o;20 return unit.ashort ==ashort21 && unit.achar ==achar22 && unit.abyte ==abyte23 && unit.abool ==abool24 && unit.along ==along25 && Float.floatToIntBits(unit.afloat) ==Float26 .floatToIntBits(afloat)27 && Double.doubleToLongBits(unit.adouble) ==Double28 .doubleToLongBits(adouble)29 &&unit.aObject.equals(aObject)30 &&equalsInts(unit.ints)31 &&equalsUnits(unit.units);32 }33

34 private boolean equalsInts(int[] aints) {35 returnArrays.equals(ints, aints);36 }37

38 private booleanequalsUnits(Unit[] aUnits) {39 returnArrays.equals(units, aUnits);40 }41

42 public inthashCode() {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 returnresult;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 returnresult;63 }64

65 private intunitsHashCode(Unit[] aUnits) {66 int result = 17;67 for (int i = 0; i < aUnits.length; i++)68 result = 37 * result +aUnits[i].hashCode();69 returnresult;70 }71 }

View Code

關鍵是如何計算hashcode值.

此外要注意如何在Java中避免equals方法的隐藏陷阱(http://coolshell.cn/articles/1051.html)

下面給出比較成熟的equals()代碼:

1 public booleanequals(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

JAVA重新對象equals方法_java對象equals方法的重寫

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 m = new HashMap();

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:

JAVA重新對象equals方法_java對象equals方法的重寫

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();

}