回顧equals() 方法 與 「==」 的區別

要想了解==和equals 的區別 ,首先要了解「值」在jvm中的存儲結構。java

值類型是存儲在內存中的堆棧(之後簡稱棧),而引用類型的變量在棧中僅僅是存儲引用類型變量的地址,而其自己則存儲在堆中eclipse

    ==操做比較的是兩個變量的值是否相等,對於引用型變量表示的是兩個變量在堆中存儲的地址是否相同,即棧中的內容是否相同。jvm

   注意 此處的equals爲重寫Object以後的方法工具

    equals操做表示的兩個變量是不是對同一個對象的引用,即堆中的內容是否相同。測試

    ==比較的是2個對象的地址,而equals比較的是2個對象的內容。this

    顯然,當equals爲true時,==不必定爲true;spa

 

1. 基本數據類型

java的基本數據類型,也稱爲原始的數據類型。它們分別是: 
byte, short, char, int, long, float, double, boolean . 
基本數據類型進行 「==」 比較時,比較的是 它們的值 是否相同。 
例如:code

int a = 10;
int b = 10
System.out.println(" (a == b) = " + (a == b));

輸出的結果爲真。 
另外須要注意的是,對於基本類型而言,它們沒有 equals() 方法,你們別上當啊對象

2. 複合數據類型(類)

1) 當 兩個對象使用 「==」 進行比較時,比較的是它們在 內存中存放的地址。 也就是說,除非是 同一個new() 出來的兩個對象(內存地址相同), 不然比較的結果都是false。具體測試代碼以下:繼承

public class Main {
    public static void main(String args[]) {
        Worker worker1 = new Worker();
        //worker2 是 worker1 的引用,同指向一個內存空間。
        Worker worker2 = worker1;
        System.out.println("(worker1 == worker2) : " + (worker1 == worker2));

        System.out.println("-------------------------");

        Worker worker3 = new Worker();
        //worker3 與 worker4 都是調用new 產生的對象,不指向同一個內存空間。
        Worker worker4 = new Worker();
        System.out.println("(worker3 == worker4) : " + (worker3 == worker4));
    }
}

class Worker {

    private String name;
    private double salary;

    public Worker() {
        this.name = "echo";
        this.salary = 0.0;
    }
    public Worker(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
}

輸出的結果:
(worker1 == worker2) : true
-------------------------
(worker3 == worker4) : false

2) 你們都知道java的全部類 都是從 java.lang.Object 這個類繼承下來,而Object 類中本來就有一個 equals() 方法。首先,咱們來看看源代碼中 Object 類的equals() 方法。具體代碼以下:

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

能夠發現,默認狀況下,當咱們調用equals() 方法時,也仍然是比較兩個對象 是否指向同一塊內存空間。 咱們 稍微 修改 上面的代碼,進行測試。具體代碼以下:

public class Main1 {
    public static void main(String args[]) {
        Worker worker1 = new Worker();
        //worker2 是 worker1的引用,同指向一個內存空間。
        Worker worker2 = worker1;
        System.out.println("worker1.equals(worker2) : " + worker1.equals(worker2));

        System.out.println("-------------------------");

        Worker worker3 = new Worker();
        //worker3 與 worker4 都是調用new 產生的對象,不指向同一個內存空間。
        Worker worker4 = new Worker();
        System.out.println("worker3.equals(worker4) : " + worker3.equals(worker4));
    }
}

class Worker {
    private String name;
    private double salary;

    public Worker() {
        this.name = "echo";
        this.salary = 0.0;
    }
    public Worker(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }
}

運行結果以下:
worker1.equals(worker2) : true
-------------------------
worker3.equals(worker4) : false
  • 家必定有疑問了,不是都說,equals() 方法比較的是 兩個對象的內容嘛? 沒錯,默認的約定是這樣的。對於咱們本身寫的類,若是想要達到這個效果,那麼就要重寫 equals()方法了。具體代碼以下: 
    (能夠直接使用 eclipse的工具,選擇本身想要進行比較的變量,自動生成 equals()方法)。

 

3. 怪異的String

上文說了,String類重寫了 equals() 方法,當調用equals()方法比較兩個String對象時,比較的是其內容,那 怪異二字 從何而來呢? 且看下面代碼:

public class Main2 {
    public static void main(String args[]) {
        String s1 = "hello world";
        String s2 = "hello world";

        System.out.println("s1.equals(s2) : " + s1.equals(s2));
        System.out.println("(s1 == s2) : " + (s1 == s2));

    }
}

運行結果以下:
s1.equals(s2) : true
(s1 == s2) : true
輸出結果說明,s1 與 s2 同指向一個 String對象。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

先不着急,咱們再修改一下上面代碼:

public class Main3 {
    public static void main(String args[]) {

        String s1 = "hello world";
        String s2 = new String("hello world");

        System.out.println("s1.equals(s2) : " + s1.equals(s2));
        System.out.println("(s1 == s2) : " + (s1 == s2));

    }
}

運行結果:
s1.equals(s2) : true
(s1 == s2) : false
輸出結果說明,s1 與 s2 不屬於同一個String對象。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

爲何出現上面這個怪異的問題? 
原來,程序在運行的時候會建立一個字符串緩衝池。 
當使用 String s2 = 「hello world」 , 
這樣的表達是建立字符串的時候,程序首先會在這個String緩衝池中尋找相同值的對象,在第一個程序中,s1先被放到了池中,因此在s2被建立的時候,程序找到了具備相同值的 s1,將s2引用 s1所引用的 對象 「hello world」。 
第二段程序中,使用了 new 操做符,它明白的告訴程序:」我要一個新的!不要舊的!」因而一個新的」hello world」 Sting對象被建立在內存中。它們的值相同,可是內存地址不一樣,一個在池中游泳,另外一個在岸邊休息。

事情還沒完,在看看下面這個例子。

public class Main4 {
    public static void main(String[] args) {
        String s1 = "hello world";
        String s2 = new String("hello world");

        s2 = s2.intern();

        System.out.println("s1.equals(s2) : " + s1.equals(s2));
        System.out.println("(s1 == s2) : " + (s1 == s2));
    }
}

運行結果以下:
s1.equals(s2) : true
(s1 == s2) : true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

怎麼會這樣??? 
原來,java.lang.String的intern()方法 ,例如 「abc」.intern()方法的返回值仍是字符串」abc」,表面上看起來好像這個方法沒什麼用處。但實際上,它作了個小動做:檢查字符串池裏是否存在」abc」這麼一個字符串,若是存在,就返回池裏的字符串;若是不存在,該方法會 把」abc」添加到字符串池中,而後再返回它的引用。

相關文章
相關標籤/搜索