Java中==、equals()、hashCode()詳解

原創(chuàng)在這里:http://yanhui.site/2017/09/09/JavaInterview%E2%80%94%E2%80%94equals%E5%92%8ChashCode%E5%92%8C==/

一、Java中的數據類型

基本數據類型
注釋:byte是 字節(jié),bit是

  • 整形:byte、int、short、long (默認int)
    byte 1 字節(jié) 8 位
    int 4 字節(jié) 32位
    short 2字節(jié) 16位
    long 8字節(jié) 64位
  • 浮點型:float、double (默認double)
    float 4 字節(jié) 32 位
    double 8字節(jié) 64位
  • 字符類型 char :2字節(jié) 16位
  • 布爾類型 boolean

引用數據類型

  • 接口
  • 數組

引用類型可以理解我我們申明一個變量,指向它所代表的對象,就是這個變量引用了這個對象,所以說是引用類型(reference type)。

二、==

== 是用來比較兩個數據是否相等。
這里需要說下數據在內存中的存儲,無論是基本數據類型還是引用類型,要存儲在內存中,都是以二進制碼的形式存儲在內存中,內存會開辟一塊空間。因此,在內存中的數據都有一個數據值和地址。

  • 如果比較的是基本數據類型,比較的是他們的數值是否相等
  • 如果比較的引用數據類型,比較的是他們的存值的地址是否相等

注意:比較的必須是相同的數據類型的兩個數據

//比如存在一個Person類
Person p= new Person("張三",23);
Person p1= new Person("張三",23);
//兩個基本類型的數據
int a=1;
int b=2;
if(a==b){//由于1!=2 所以輸出false
  //dosomething
}
//比較引用類型,比較地址,那么很顯然,在堆內存中,new出來了兩塊區(qū)域
//這兩塊的區(qū)域的地址顯然是不同的,因此輸出為false
if(p1==p2){ //false
//dosomething
}

== 我們基本已經知道了它的作用了,但是我們一般往HashMap中存入引用數據時,我們不想知道這個數據的地址是否已經存在,我們只想知道這個數據是否存在。如果存在我們get(key)取出來,供我們后續(xù)使用,如果不存在,我再存入。這時equals()就應運而生了。

三、equals()

equals()方法是Object中的一個方法,也就是萬物基類中的方法,那么也就是說每一個類中都會有這個方法。

public class Person {

    private String name;
    private int age;

    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
}
public class Main5Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main5);


        Person p1 = new Person("張三", 18);
        Person p2 = new Person("張三", 18);

        boolean b = p1 == p2;
        boolean b1 = p1.equals(p2);

        Log.e("比較結果b", "=" + b);
        Log.e("比較結果b1", "=" + b1);
    }
}
//結果:false  false

到這里有疑惑了,equals()方法不是比較的內容嗎,那我的理解是p1==p2返回false,p1.equals(p2)應該返回true,他們內容相同啊。那我們來看下Object類下的equals源碼。

public boolean equals(Object obj) {
       return (this == obj);
}

從源碼我可以知道,如果是引用類型,還是比較的地址,所以兩個對象的地址不相等,返回false沒有毛病。

所以我們在我們的類中一般都要重寫equals方法,自己比較內容是否相同,就拿剛才的Person類來說,如下:

public class Person {

    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //重寫equals方法,AS幫我們實現了, 比較內容是否相同
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        if (age != person.age) return false;
        return name != null ? name.equals(person.name) : person.name == null;
    }
}

四、hashCode()

說到hashCode()方法,大家都知道他是用來返回hash值的方法。那什么是hash值,他又有什么作用呢?其實我也不是很清楚,我目前的理解是他就是類似于一個對象的屬性,那他是干什么用的呢?hash值是在HashMap、HashTable、HashSet的內部存取元素啊等相關操作時用到,目的就是提高他們的內部性能。

好了,大體了解了hash值之后,你還需要知道這樣一個觀念。Android系統中的類都是有關聯的,他們是互相約束配合工作的。比如萬物之基類的Object類中有許多方法,有的方法使用final修飾的,子類不能重寫。有的是沒有用final修飾的,子類可以重寫。那么子類就可以隨意重寫嗎?不是的,Object類是有規(guī)范約束的,意思就是如果你要重寫我的方法,必須要遵守一二三等等幾條規(guī)定,如果你不按規(guī)定辦事,可能就會影響到他人了。

了解了上面的概念后,就要說下Object類中,針對equals()方法,它定了哪些規(guī)定呢。
Object規(guī)范:在復寫equals方法時,你必須遵守下面的約定。

  1. 自反性: 對于任何非null的引用值x,x.equals(x)必須返回true。
  2. 對稱性:對于任何非null的引用值x和y,當且僅當x.equals(y)返回true時,那么y.equals(x)必須返回true。
  3. 傳遞性:對于任何非null的引用值x、y、z,如果x.equals(y)返回true,y.equals(z)也返回true,那么x.equals(z)必須返回true。
  4. 一致性:對于任何非null的引用值x和y,只要equals的比較操作時,對象中的所有信息沒有被修改,多次調用x.equlas(y)就會一直的返回true,或者一致的返回false。

對于任何非null的引用值x,x.equals(null)必須返回false。

Object規(guī)范:在復寫hashCode方法時,你必須遵守下面的約定。

  1. 在應用程序運行期間,只用對象的equals方法比較操作所用到的信息沒有被修改,那么對同一個對象多次調用,hashCode方法都必須始終如一的返回同一個數。在同一個程序的多次執(zhí)行過程中,每次執(zhí)行所返回的整數可以不一致。
  2. 如果兩個對象根絕equals方法比較是相等的,那么調用兩個對象的任意一個對象的hashCode方法都必須產生同樣的整數結果。
  3. 如果兩個對象根據equals方法比較不相等,那么調用兩個對象中任意一個對象的hashCode方法,則不一定產生不同的整數結果。但是程序員應該知道,給不相等的對象產生不同的整數結果,有可能提高散列表的性能。

知道這兩條約定了,那么我們還要知道一個非常重要的知識點。就是一個類中如果復寫了equals方法,必須也要復寫hashCode方法。

那我們?yōu)樯兑獜蛯慼ashCode方法呢?這個就是約定俗成的東西,如果你不這樣做就會產生錯誤,產生啥錯誤呢,我們來看下:

Person p1 = new Person("張三", 18);
Person p2 = new Person("張三", 18);

我們還是用上面的Person類,只復寫了equals方法,沒有復寫hashCode方法。根據hashCode的第二條約定,如果兩個對象的equals方法相等,那么hashCode必須返回相同的整數。現在我們的p1.equals(p2)返回true,但是hashCode就返回的是相同的整數嗎?

int h1 = p1.hashCode();
int h2 = p2.hashCode();

我們可以打印出兩個hashcode值來看下,結果是不一定相等。如果不相等就違背了第二條約定。

HashMap hashMap = new HashMap();
hashMap.put(p1,"張三");

我們再來看下,我往hashmap中存了了一個string類型的value值,而鍵是類型是Person的。我的期望是如果我用 hashMap.get(p2);,應該返回的是 張三,但是我們可以試下,發(fā)現返回的null。為什么會返回null呢,那是因為hashmap在取值的時候,要先看有沒有這個key值。找個這個key值的時候,他先用這個key值的hash值比較,如果hash值不相等,直接返回null,即沒有找到。如果key值的hash值相同,hashmap會繼續(xù)比較key值的內容是否都相同,如果相同說明找到了,如果不同返回null,說明沒找到。

通過上面的兩個例子,我們知道了為啥復寫equals方法時必須同時復寫hashCode方法。

結束……

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容