參考淺談Java中的equals和==
Java 中正確使用 hashCode 和 equals 方法
一、==
結論:
如果作用于基本數據類型的變量,則直接比較其存儲的 “值”是否相等;
如果作用于引用類型的變量,則比較的是所指向的對象的地址
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int n=3;
int m=3;
System.out.println(n==m);
String str = new String("hello");
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1==str2);
str1 = str;
str2 = str;
System.out.println(str1==str2);
}
}
//ture false true
二、equals方法
1.如果沒有對equals方法進行重寫,則比較的是引用類型的變量所指向的對象的地址;下面是Object類中equals方法的實現:
Paste_Image.png
2.equals方法不能作用于基本數據類型的變量。諸如String、Double,Date,Integer,Date等類對equals方法進行了重寫的話,比較的是所指向的對象的內容。下面是String類中equals方法的具體實現:
Paste_Image.png
三、haseCode
public class Employee
{
private Integer id;
private String firstname;
private String lastName;
private String department;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
上面的Employee類只是有一些非常基礎的屬性和getter、setter.現在來考慮一個你需要比較兩個employee的情形。
public class EqualsTest {
public static void main(String[] args) {
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setId(100);
e2.setId(100);
//Prints false in console
System.out.println(e1.equals(e2));
}
}
毫無疑問,上面的程序將輸出false,但是,事實上上面兩個對象代表的是通過一個employee。真正的商業邏輯希望我們返回true。 為了達到這個目的,我們需要重寫equals方法。
public boolean equals(Object o) {
if(o == null)
{
return false;
}
if (o == this)
{
return true;
}
if (getClass() != o.getClass())
{
return false;
}
Employee e = (Employee) o;
return (this.getId() == e.getId());
}
測試一下:
import java.util.HashSet;
import java.util.Set;
public class EqualsTest
{
public static void main(String[] args)
{
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setId(100);
e2.setId(100);
//Prints 'true'
System.out.println(e1.equals(e2));
Set<Employee> employees = new HashSet<Employee>();
employees.add(e1);
employees.add(e2);
//Prints two objects
System.out.println(employees);
}
}
如果兩個employee對象equals返回true,Set中應該只存儲一個對象才對,問題在哪里呢? 我們忘掉了第二個重要的方法hashCode()。就像JDK的Javadoc中所說的一樣,如果重寫equals()方法必須要重寫hashCode()方法。我們加上下面這個方法,程序將執行正確。
@Override
public int hashCode()
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId();
return result;
}
需要注意的事情
- 盡量保證使用對象的同一個屬性來生成hashCode()和equals()兩個方法。在我們的案例中,我們使用員工id。
- eqauls方法必須保證一致(如果對象沒有被修改,equals應該返回相同的值)
- 任何時候只要a.equals(b),那么a.hashCode()必須和b.hashCode()相等。兩者必須同時重寫。
- 如果你使用ORM處理一些對象的話,你要確保在hashCode()和equals()對象中使用getter和setter而不是直接引用成員變量。因為在ORM中有的時候成員變量會被延時加載,這些變量只有當getter方法被調用的時候才真正可用。例如在我們的例子中,如果我們使用e1.id == e2.id則可能會出現這個問題,但是我們使用e1.getId() == e2.getId()就不會出現這個問題。