1. 運算符 ==
在Java中數據類型分爲兩大類:基本數據類型(byte,short,char,int,long,float,double,boolean)和引用數據類型(類、接口和數組)。
- 基本數據類型
在基本數據類型中,== 操作比較的是兩個變量的值是否相等。 - 引用數據類型
在引用數據類型中,== 操作比較的是兩個對象在內存中的引用地址。引用類型在棧中存放的是對象引用(地址),對象是放在堆中。
2. Equals 方法
equals 是 Object類默認提供的方法。
- 沒有覆蓋情況
主要用於判斷對象的內存地址是不是同一個地址(是不是同一個對象)
// Object 類equals 源碼
public boolean equals(Object obj) {
return (this == obj);
}
- 覆蓋情況
要是覆蓋equals方法情況下,則根據具體的代碼來確定equals方法的作用。一般都是通過對象的內容是否相等來判斷對象是否相等。
// String 類 equals 源碼
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
判斷相等的步驟:
1. 比較兩個String對象是否爲同一對象,如果是就直接返回true
2. 如果不是同一對象,先確定傳入的對象是否是String類型,如果是,則比較兩對象的字符序列
3. 遍歷過程中只要有一個字符不相同,就返回false,否則返回true
補充 :覆蓋equals需遵守通俗約定
- 自反性: 對於任何非null的引用值x, x.equals(x)必須返回true
- 對稱性: 對於任何非null的引用值x和y, 當且僅當y.equals(x)返回true時,x.equals(y)必須返回true
- 傳遞性: 對於任何非null的引用值x,y,z, 如果x.equals(y)爲true,並且y.equals(z)也返回true,那麼x.equals(z)也必須返回true
- 一致性: 對於任何非null的引用值x和y, 只要equals的比較操作在對象中所用的信息沒有被修改,多次調用x.equals(y)就會一致地返回true,或者false
- 對於任何非null的引用值x, x.equals(null)必須返回false
3.HashCode
hashCode方法返回值是Int型數據,這個值稱爲哈希碼(散列碼)。作用:確定該對象在散列表中的索引位置。
// Object 類的源碼
public native int hashCode();
應用
在Java裏集合可以存儲大量的數據,那麼Set集合中元素是無序且不可重複的,那麼Set集合如何來保證元素不重複呢?通過迭代來 equals() 是否相等。數據量小還可以接受,當我們的數據量大的時候效率可想而知。hashCode 提供瞭解決方案。
hashCode是一個本地方法,它的實現與本地機器有關。當我們向一個集合中添加某個元素,集合會首先調用 hashCode 方法,這樣就可以直接定位它所存儲的位置,若該處沒有其他元素,則直接保存。若該處已經有元素存在,就調用 equals 方法來匹配這兩個元素是否相同,相同則不存,不同則散列到其他位置。這樣處理,當我們存入大量元素時就可以大大減少調用 equals() 方法的次數,極大地提高了效率。
hashCode 方法和equals 方法關係
Java 中,當用到HashMap、HashSet、HashTable這類的集合框架時,比如,將自己新建的類作爲 HashMap 的 key。這種情況下,需要重寫hashCode和equals方法。
例子
public class EqHashCode {
public static void main(String[] args) {
Student stu=new Student("小米","一班");
Student stu1=new Student("小米","一班");
HashMap<Student, String> hashMap = new HashMap<>();
hashMap.put(stu,stu.className);
hashMap.put(stu1,stu1.className);
System.out.println(hashMap.size());
System.out.println(stu==stu1);
System.out.println(stu.equals(stu1));
}
}
public class Student {
public String name;
public String className;
public Student(String name, String className) {
super();
this.name = name;
this.className = className;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Student) {
Student stu = (Student) obj;
if (name.equals(stu.name) && className.equals(stu.className)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
int result = 17;// 非0 任選
result = 31 * result + name.hashCode();
result = 31 * result + className.hashCode();
return result;
}
}
運行結果:
第一次equals 方法沒有覆蓋情況下,hashMap size爲2;第二次覆蓋equals 方法下,hashMap size爲1
總結
- 如果兩個對象相等,則hashcode一定也是相同的
- 如果兩個對象相等,則兩個對象分別調用equals方法都返回true
- 兩個對象有相同的hashcode值,它們也不一定是相等的
- equals 方法被覆蓋過,則 hashCode 方法也必須被覆蓋
- hashCode() 的默認行爲是對堆上的對象產生獨特值。如果沒有重寫 hashCode(),則該 類的兩個對象無論如何都不會相等(即使這兩個對象指向相同的數據)