天天看點

Java 的 equals 和 ==Java 的 equals 和 ==

Java 的 equals 和 ==

引言

  在 Java 程式設計中,我們常會用 equals 方法或 == 運算符來比較兩個東西是否相等,若相等則傳回 true,否則傳回 false。

  那麼他們是如何工作的呢,下面來細說一下。

== 比較運算符

  首先說說 == 這個比較運算符,他可以作用于對象變量也可以作用于基本類型的變量,那麼是對于這兩種類型,分别是如何工作的呢。

作用在引用變量上

先看如下代碼:

public static void test() {
    Object obj1 = new Object();
    Object obj2 = new Object();
    System.out.println(obj1 == obj2);

    String s1 = "hello";
    String s2 = "hello";
    String s3 = new String("hello");
    System.out.println(s1 == s2);
    System.out.println(s1 == s3);

    Integer i1 = ;
    Integer i2 = ;
    Integer i3 = new Integer();
    Integer i4 = ;
    Integer i5 = ;
    int i6 = ;
    System.out.println(i1 == i2);
    System.out.println(i1 == i3);
    System.out.println(i4 == i5);
    System.out.println(i6 == i5);
}
           

輸出結果:

false
    true
    false
    true
    false
    false
    true
           

  相信大家都知道,當使用 == 比較符作用于兩個引用變量上時,當兩個引用變量是指向同一個對象時,它則會傳回 ture;否則傳回 false;不過這實際上比較的是引用變量的儲存的對象位址是否相等(引用變量儲存的是對象的位址)

  下面分析作用不同類型的對象時的表現

  

普通 obj 對象

  在前面的例子中,obj1 和 obj2 比較,因為它們不是同一個對象,儲存的位址也不同,是以傳回 false。

String 對象

  s1、s2 和 s3 比較,他們的内容都是 hello,但前者比較傳回 true,而後者比較傳回 false。原因主要是兩者定義的方式不同,字元串在堆中存在一個字元串常量池,對于編譯期能确定的字元串,都會在常量池中儲存該常量,是以 s1,s2 實際上引用的都是常量池的常量,是以他們傳回 true。而對于 s3,它是運作時建立的,是以是一個新對象,與 s1 引用的對象不是同一個對象,是以比較傳回 false。

包裝對象

  包裝對象 Integer 類的比較,i1 和 i2 是通過自動裝箱的方式進行的,即它會調用 valueOf 方法來建立 Integer 對象,我們來看看 valueOf 方法的實作。

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];

    return new Integer(i);
}
           

  從方法裡面可以看出,Integer 中也實作了一個緩沖池(對于 Boolean、Character、Byte、Short、Long 内部也采用了緩沖池,而 Float 和 Double) 則沒有,當 i 位于緩沖池中(預設是 -128 ~ 127),則直接傳回緩沖池中的對象執行個體,否則建立一個新執行個體。

   建立 i1 和 i2 時,i 為 1,在緩沖池的範圍内,是以它們都指向緩沖池的同一個對象,是以傳回 true;i3 則是使用 new 來建立的新對象,是以比較傳回 false;i4 和 i5 因為 i = 128 不在緩沖池的範圍内,是以都是 不同的對象,是以傳回 false;i6 是基本類型,與 i5 進行比較時,i5 會自動拆箱成基本類型,是以兩個 int 都為 128 的變量是相等的,傳回 true。

作用于基本類型變量

先看如下代碼:

public static void baseTest() {
    byte b = ;
    short s = ;
    int i = ;
    long l = l;
    float f = f;
    double d = ;

    System.out.println(b == s);
    System.out.println(s == i);
    System.out.println(i == l);
    System.out.println(i == f);
    System.out.println(i == d);
    System.out.println(l == i);
    System.out.println(l == f);
    System.out.println(l == d);
    System.out.println(f == d);
}
           

輸出結果:

  

  使用 == 運算符作用于基本類型時,當比較的是相同類型變量時,會直接比較值的大小;但作用于不同類型的變量時,會發生隐式類型轉換,轉換成大類型,然後繼續比較值。

類型轉換的規則:

Java 的 equals 和 ==Java 的 equals 和 ==

equals 方法

  equals 方法也是用于比較兩個對象是否相等,每一個 Object 對象都有它的 equals 方法,在 Object 類的預設實作如下:

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

  當然子類也可以通過重寫該方法來設計對象相等的規則,一般來說重寫 equals 方法,也必須重寫對象的 hashcode 方法。

  從 Object 的源碼可知,若子類沒有重寫 equals 方法,則若兩個對象不是同一個對象,則會傳回false;那麼我們現在來分析一下 Java 類庫中,一些常用對象的 equals 方法是如何工作的。

String 對象

先看如下代碼:

public static void testString() {
    String s1 = "hello";
    String s2 = new String("hello");
    System.out.println(s1.equals(s2));
}
           

輸出結果:

  從前面分析 == 運算符時,我們知道 s1 和 s2 不是同一個對象,但是它們的 equals 方法卻傳回true 了,現在我們來看看 String 類的 equals 方法源碼實作。

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = ;
            while (n-- != ) {
                if (v1[i] != v2[i])
                  return false;
                    i++;
            }
            return true;
        }
    }

    return false;
}
           

  從源碼可以看出,若兩個對象是同一個對象,仍然會傳回 ture;若不是時,首先通過 instanceof 運算符判斷是否是 String 對象,若是則會對 String 變量的底層數組進行比較,若數組的元素值都一樣(即字元串一樣),則會傳回true,反之傳回 false。

包裝對象

先看如下代碼:

public static void test() {
    Byte b = new Byte((byte));
    Short s = new Short((short));
    Integer i1 = ;
    Integer i2 = new Integer();
    Long l = new Long();
    Float f = new Float();
    Double d = new Double();

    System.out.println(b.equals(i1));
    System.out.println(s.equals(i1));
    System.out.println(i1.equals(i2));
    System.out.println(i1.equals());
    System.out.println(l.equals(f));
    System.out.println(f.equals(d));
}
           

輸出結果:

false
false
true
true
false
false
           

  包裝類型的 equals 方法,都是先用 instanceof 運算符判斷是否是對應的包裝類型,若是,則判斷值是否相等,相等則傳回 true;否則傳回 false。

總結

  對于 == 和 equals 方法,都是用于比較兩個變量是否相等。== 可用于比較引用變量,也可用于比較基本類型變量。當用于比較引用變量時,比較的是兩個變量是否引用同一個對象;基本類型比較的是值是否相等,當類型不一緻時,會發生隐式類型轉換。

  equals 方法是 Object 的基本方法,預設實作是當兩個對象不是同一個對象,則會傳回 false。另外可以通過重寫 equals 方法來更改對象相等的原則。如:String 的 equals 方法會比較底層字元數組的内容是否相等,包裝類則會先通過 instanceof 運算符來判斷是否同一種包裝類型,再比較值是否相等。一般來說,重寫了對象 equals 方法,最好也重寫對象的 hashcode 方法,Java 類庫的 Hash 實作是依賴于這兩個方法來實作的。