深入理解Java的==和equals

關系操作符==

關系操作符== ,適用于所有的基本數據類型,同時也適用于對象。

  • == 用于基本數據類型,比較的是數據的值

Java中有8種基本數據類型,其中有4種整型(int ,short,long,byte)、2種浮點類型(float,double)、1種用于表示Unicode編碼的字符單元的字符類型char和1種用于表示真值的boolean類型。

下面對基本數據類型進行相等性測試:

public class Test {
  public static void main(String[] args) {
      boolean b1 = true;
      boolean b2 = true;
      System.out.println("b1 == b2: "+(b1==b2));
      char c1 = 'c';
      char c2 = 'c';
      System.out.println("c1 == c2: "+(c1==c2));
      byte by1 = 1;
      byte by2 =1;
      System.out.println("by1 == by2: "+(by1==by2));
      short sh1 = 2;
      short sh2 =2;
      System.out.println("sh1 == sh2: "+(sh1==sh2));
      int n1 = 1;
      int n2 =1;
      System.out.println("n1 == n2: "+(n1==n2));
      long l1 = 1L;
      long l2 = 1L;
      System.out.println("l1 == l2: "+(l1==l2));
      float f1 =1F;
      float f2 = 1F;
      System.out.println("f1 == f2: "+(f1==f2));
      double d1 = 3.14;
      double d2 = 3.14;
      System.out.println("d1 == d2: "+(d1==d2));
   }
}

結果如下:

b1 == b2: true
c1 == c2: true
by1 == by2: true
sh1 == sh2: true
n1 == n2: true
l1 == l2: true
f1 == f2: true
d1 == d2: true

上面的測試都是對同一類型的值進行比較(如 by1與by2都是byte類型的整數)
如果,我們對不同類型的數字進行比較會得出什么結果?

 public class Test {
    public static void main(String[] args) {
      int n= 100;
      byte b = 100;
      long l = 100L;
      short s = 100;
      System.out.println("n==b: "+ (n==b));
      System.out.println("b==l: "+ (b==l));
      System.out.println("l==s: "+(l==s));

      float f1 = 3.14F;
      float f2 =100F;
      double d1 = 3.14;
      double d2 = 100;
      System.out.println("f1==d1: "+(f1==d1));
      System.out.println("f2==n: "+(f2==n));
      System.out.println("d2==n:"+(d2==n));
  }
}

結果:

n==b: true
b==l: true
l==s: true
f1==d1: false
f2==n: true
d2==n:true

結論:

1、不同類型的整數之間可以進行相等性比較。
2、不同類型的小數之間不要使用==比較,因為精度不同。
3、 整數和小數可以進行相等性比較,整數會自動轉成相應的浮點類型。

  • == 用于對象,比較的是對象的引用

先看個下面這個例子,創建兩個字符串對象s1和s2,然后進行相等性比較。

public class Test {
    public static void main(String[] args) {
     String s1 = new String("abc");
     String s2 = new String("abc");
     System.out.println(s1 == s2);
    }
}

結果: false

雖然s1和s2的值相等,但是s1和s2的引用卻是不同時的,這是兩個對象,因此返回false。

接下來看個奇怪的問題:

public class Test {
      public static void main(String[] args) {
         String s1 = "abc";
         String s2 = "abc";
         System.out.println(s1 == s2);
      }
  }

你猜出正確結果嗎?

你可能會想,這不是生成了兩個字符串嗎,一定是不相等的。

輸出結果是:

true

這是為什么?
原因是:在java中,字符串是不可修改的,是不可變的。修改字符串實際是將變量引用了新的字符串。不可變字符串有個優點:編譯器可以讓字符串共享。
上面的代碼可以這么理解:當創建s1時,存儲池放置了一個字符串,當創建s2時,發現創建的是同樣的字符串,就不再放入字符串了,因為這樣會重復,所以s2就直接引用了存儲池中已經存在的字符串。
如果s1改變了,那么存儲池就會再放入一個新字符串,這時候,s1,s2指向的字符串地址就不一樣了。

  • ==用于包裝器對象
public class Test {
   public static void main(String[] args) {
     Integer a =1000;
     Integer b=1000;
     System.out.println(a==b);

     Integer c =100;
     Integer d=100;
     System.out.println(c==d);
  }
}

運行結果:

false
true

出現這種現象的原因是:自動裝箱規范要求boolean、byte、char<=127,介于-128~127之間的short和int被包裝到固定的對象中。

因此,在比較兩個包裝器對象時調用equals方法。

equals方法

equals方法適用于對象,而不能用于基本數據類型。

  • 自定義類的實例對象equals操作
class  Person{}

public class Test {
    public static void main(String[] args) {
       Person p1 = new Person();
       Person p2 = new Person();
       System.out.println(p1.equals(p2));
    }
}

結果是:

false

Java中所有類都默認繼承Object,而Object類中的equals方法會判斷兩個對象是否具有相同的引用。如果兩個對象具有相同的引用,它們一定是相等的。因此,兩個對象的equals操作默認是比較引用。

Object類中的equals源碼如下所示:

public boolean equals(Object obj) {
    return (this == obj);
}
  • 字符串的equals操作
public class Test {
     public static void main(String[] args) {
         String s1 = "noshower";
         String s2 = "noshower";
         System.out.println(s1.equals(s2));
     }
}

結果如下:

 true

String的equals方法重寫了,覆蓋了Object類的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 = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

從源碼中可以看出String類的equals方法,先是比較兩個變量是否指向同一個引用,如果是,直接返回相等。如果不是,就要判斷equals括號內的變量,是否是String的實例,如果不是直接返回不相等。如果是String的實例,就比較兩個變量代表的字符串長度是否相等,如果不相等就返回不相等的結果。如果長度相等,就把字符串轉成char數組,比較每個字符是否相等。如果都相等,就返回相等的結果。如果有一個字符不相等,就返回不相等的結果。

由此我們可以得出,String的equals方法對相同引用的變量和不同引用,但是值相等的變量,都返回true。

我們再來看一個有趣的問題:

public class Test {
    public static void main(String[] args) {
        String s = "noshower";
        System.out.println(s+"2" == "noshower2");
        System.out.println("noshower2".equals(s+"2"));
    }
}

結果如下:

false
true

這是為什么呢?

如果兩個字符串放置在同一個位置上,它們必然相等。但是,完全有可能將內容相同的多個字符串的拷貝放置在不同的位置上。所以s+"2" 與"noshower2"放置在不同的位置。

實際上,只有字符串常量是共享的,而+或substring等操作產生的結果并不是共享的。

因此,千萬千萬不要用==測試字符串的相等性

  • 基本類型的包裝類equals

這里只舉例Integer包裝類,因為其他包裝類的實現邏輯都是一樣的。都是先比較某個變量是不是這個包裝類的實例,如果不是,返回false。否則,比較值是否相等。如果相等,就返回true。否則返回false。

public class Test {
    public static void main(String[] args) {
        Integer n1 =new Integer(47);
        Integer n2 =new Integer(47);
        System.out.println(n1==n2);
        System.out.println(n1.equals(n2));
    }
}

結果如下:

false
true

不是同一個引用,所以==返回false。值相等,所以equals返回true。

Integer類equals方法源碼如下:

 public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

正如我上面所說的,先比較是不是同一個類型,再比較值是否相等。

其他幾個包裝類就不一一講述了。這里貼上,它們的equals源碼。

Short

public boolean equals(Object obj) {
    if (obj instanceof Short) {
        return value == ((Short)obj).shortValue();
    }
    return false;
}

Long

public boolean equals(Object obj) {
    if (obj instanceof Long) {
        return value == ((Long)obj).longValue();
    }
    return false;
}

Byte

public boolean equals(Object obj) {
    if (obj instanceof Byte) {
        return value == ((Byte)obj).byteValue();
    }
    return false;
}

Float

public boolean equals(Object obj) {
    return (obj instanceof Float)
           && (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
}

Double

 public boolean equals(Object obj) {
    return (obj instanceof Double)
           && (doubleToLongBits(((Double)obj).value) ==
                  doubleToLongBits(value));
}

Character

 public boolean equals(Object obj) {
    if (obj instanceof Character) {
        return value == ((Character)obj).charValue();
    }
    return false;
}

Boolean

public boolean equals(Object obj) {
    if (obj instanceof Boolean) {
        return value == ((Boolean)obj).booleanValue();
    }
    return false;
}

完畢??!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,278評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,241評論 2 375

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,726評論 18 399
  • java筆記第一天 == 和 equals ==比較的比較的是兩個變量的值是否相等,對于引用型變量表示的是兩個變量...
    jmychou閱讀 1,511評論 0 3
  • 集合框架: 1)特點:存儲對象;長度可變;存儲對象的類型可不同2)Collection(1)List:有序的;元素...
    Demo_Yang閱讀 1,279評論 0 4
  • java中String的常用方法 1、length()字符串的長度 例:char chars[]={'a','b'...
    赤赤有名閱讀 2,090評論 0 10
  • equals方法和==的區別 首先大家知道,String既可以作為一個對象來使用,又可以作為一個基本類型來使用。這...
    加油小杜閱讀 385評論 0 0