equals和==區(qū)別(簡單介紹了一下裝箱和拆箱操作)

引入

==

  • 基本數(shù)據(jù)類型(也稱原始數(shù)據(jù)類型) :byte,short,char,int,long,float,double,boolean。他們之間的比較,應(yīng)用雙等號(hào)(==),比較的是他們的值。
  • 復(fù)合數(shù)據(jù)類型(類):當(dāng)他們用(==)進(jìn)行比較的時(shí)候,比較的是他們?cè)趦?nèi)存中的存放地址(確切的說,是堆內(nèi)存地址)。
  • 注:對(duì)于第二種類型,除非是同一個(gè)new出來的對(duì)象,他們的比較后的結(jié)果為true,否則比較后結(jié)果為false。因?yàn)槊縩ew一次,都會(huì)重新開辟堆內(nèi)存空間。

equals

  • JAVA當(dāng)中所有的類都是繼承于Object這個(gè)超類的,在Object類中定義了一個(gè)equals的方法,這個(gè)方法的初始行為是比較對(duì)象的內(nèi)存地址,但在一些類庫當(dāng)中這個(gè)方法被復(fù)寫了,如String、Integer、Date。在這些類當(dāng)中equals有其自身的實(shí)現(xiàn),而不再是比較類在堆內(nèi)存中的存放地址了。
    所以說,對(duì)于復(fù)合數(shù)據(jù)類型之間進(jìn)行equals比較,在沒有覆寫equals方法的情況下,他們之間的比較還是內(nèi)存中的存放位置的地址值,跟雙等號(hào)(==)的結(jié)果相同;如果被復(fù)寫,按照復(fù)寫的要求來。

小結(jié)

  • “==”比較的是值【變量(棧)內(nèi)存中存放的對(duì)象的(堆)內(nèi)存地址】
  • equal用于比較兩個(gè)對(duì)象的值是否相同【不是比地址】
  • 【特別注意】Object類中的equals方法和“==”是一樣的,沒有區(qū)別,而String類,Integer類等等一些類,是重寫了equals方法,才使得equals和“==不同”,所以,當(dāng)自己創(chuàng)建類時(shí),自動(dòng)繼承了Object的equals方法,要想實(shí)現(xiàn)不同的等于比較,必須重寫equals方法。
  • "=="比"equal"運(yùn)行速度快,因?yàn)?=="只是比較引用.

Integer 和 int

代碼塊

public class Test {
    public static void main(String args[]){
        test1();
        test2();
    }

    public static  void test2(){
        System.out.println("既有基本數(shù)據(jù)類型,又有對(duì)應(yīng)的類(這里用Integer和int舉例 1231):");
        Integer a1 = new Integer(1231);
        Integer a2 = new Integer(1231);
        System.out.println("Integer new Integer");
        System.out.println("== —> "+(a1 == a2));//new 出來兩個(gè)對(duì)象,==比較的是地址
        System.out.println("equals —> "+(a1.equals(a2)));//equals比較的是值

        Integer b1 = 1231;
        Integer b2 = 1231;//這里會(huì)調(diào)用Integer.valueof();
        System.out.println("Integer 直接賦值:");
        System.out.println("== —> "+(b1 == b2));//b1、b2自動(dòng)裝箱產(chǎn)生的對(duì)象,其值都是1231,那么這里很特殊的是1231正好不在-128<=i7<=127這個(gè)范圍內(nèi)的,那么會(huì)重新new出一個(gè)對(duì)象
        System.out.println("equals —> "+(b1.equals(b2)));

        int c1 = 1231;
        int c2 = 1231;
        System.out.println("基本數(shù)據(jù)類型int 直接賦值:");
        System.out.println("== —> "+(c1 == c2));//“==”對(duì)于基本數(shù)據(jù)類型,判斷兩個(gè)變量的值是否相等
        System.out.println("沒有equals方法");

        int d1 = new Integer(1231);
        int d2 = new Integer(1231);
        System.out.println("基本數(shù)據(jù)類型int new Integer:");
        System.out.println("== —> "+(d1 == d2));//c1、c2拆箱產(chǎn)生的對(duì)象,調(diào)用的是Integer.intValue的方法
        System.out.println("沒有equals方法");

        int e1 = 1231;
        int e2 = new Integer(1231);
        System.out.println("一個(gè)int new Integer,一個(gè)直接賦值");
        System.out.println("== —> "+(e1 == e2));
        System.out.println("沒有equals方法");

        Integer f1 = 1231;
        Integer f2 = new Integer(1231);
        System.out.println("一個(gè)Integer new Integer,一個(gè)Integer直接賦值");
        System.out.println("== —> "+(f1 == f2));//f1是從IntegerCache取的數(shù)據(jù),而f2是new出來的一個(gè)對(duì)象,自然不一樣
        System.out.println("equals —> "+(f1.equals(f2)));
    }

    public static  void test1(){
        System.out.println("既有基本數(shù)據(jù)類型,又有對(duì)應(yīng)的類(這里用Integer和int舉例 123):");
        Integer a1 = new Integer(123);
        Integer a2 = new Integer(123);
        System.out.println("Integer new Integer");
        System.out.println("== —> "+(a1 == a2));//new 出來兩個(gè)對(duì)象,==比較的是地址
        System.out.println("equals —> "+(a1.equals(a2)));//equals比較的是值

        Integer b1 = 123;
        Integer b2 = 123;//這里會(huì)調(diào)用Integer.valueof();
        System.out.println("Integer 直接賦值:");
        System.out.println("== —> "+(b1 == b2));//b1、b2自動(dòng)裝箱產(chǎn)生的對(duì)象,其值都是123,那么這里很特殊的是123正好在-128<=i7<=127這個(gè)范圍內(nèi)的,那么會(huì)去IntegerCache中取,既然都是去IntegerCache中去取,那么自然該對(duì)象應(yīng)該是一個(gè)對(duì)象,那么再堆中的地址應(yīng)該是一樣的,所以在判讀兩個(gè)對(duì)象是不是== 的時(shí)候,會(huì)輸出true
        System.out.println("equals —> "+(b1.equals(b2)));

        int c1 = 123;
        int c2 = 123;
        System.out.println("基本數(shù)據(jù)類型int 直接賦值:");
        System.out.println("== —> "+(c1 == c2));//“==”對(duì)于基本數(shù)據(jù)類型,判斷兩個(gè)變量的值是否相等
        System.out.println("沒有equals方法");

        int d1 = new Integer(123);
        int d2 = new Integer(123);
        System.out.println("基本數(shù)據(jù)類型int new Integer:");
        System.out.println("== —> "+(d1 == d2));//c1、c2拆箱產(chǎn)生的對(duì)象,調(diào)用的是Integer.intValue的方法
        System.out.println("沒有equals方法");

        int e1 = 123;
        int e2 = new Integer(123);
        System.out.println("一個(gè)int new Integer,一個(gè)直接賦值");
        System.out.println("== —> "+(e1 == e2));
        System.out.println("沒有equals方法");

        Integer f1 = 123;
        Integer f2 = new Integer(123);
        System.out.println("一個(gè)Integer new Integer,一個(gè)Integer直接賦值");
        System.out.println("== —> "+(f1 == f2));//f1是從IntegerCache取的數(shù)據(jù),而f2是new出來的一個(gè)對(duì)象,自然不一樣
        System.out.println("equals —> "+(f1.equals(f2)));
    }
}

運(yùn)行結(jié)果

既有基本數(shù)據(jù)類型,又有對(duì)應(yīng)的類(這里用Integer和int舉例 123):
Integer new Integer
== —> false
equals —> true
Integer 直接賦值:
== —> true
equals —> true
基本數(shù)據(jù)類型int 直接賦值:
== —> true
沒有equals方法
基本數(shù)據(jù)類型int new Integer:
== —> true
沒有equals方法
一個(gè)int new Integer,一個(gè)直接賦值
== —> true
沒有equals方法
一個(gè)Integer new Integer,一個(gè)Integer直接賦值
== —> false
equals —> true
既有基本數(shù)據(jù)類型,又有對(duì)應(yīng)的類(這里用Integer和int舉例 1231):
Integer new Integer
== —> false
equals —> true
Integer 直接賦值:
== —> false
equals —> true
基本數(shù)據(jù)類型int 直接賦值:
== —> true
沒有equals方法
基本數(shù)據(jù)類型int new Integer:
== —> true
沒有equals方法
一個(gè)int new Integer,一個(gè)直接賦值
== —> true
沒有equals方法
一個(gè)Integer new Integer,一個(gè)Integer直接賦值
== —> false
equals —> true

源碼分析
Integer裝箱源碼(主要是Integer.valueOf方法)

    /**
     * Returns an {@code Integer} instance representing the specified
     * {@code int} value.  If a new {@code Integer} instance is not
     * required, this method should generally be used in preference to
     * the constructor {@link #Integer(int)}, as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     *
     * @param  i an {@code int} value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

IntegerCache類

/**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

數(shù)值在-128<=x<=127這個(gè)范圍內(nèi)的,那么會(huì)去IntegerCache中取。超過這個(gè)范圍回去new一個(gè)對(duì)象。
Integer拆箱源碼(主要是Integer.intValue方法)

/**
     * Returns the value of this {@code Integer} as an
     * {@code int}.
     */
    public int intValue() {
        return value;
    }

從源碼可以看出,當(dāng)包裝器類型和基本數(shù)據(jù)類型進(jìn)行“==”比較時(shí),包裝器類型會(huì)自動(dòng)拆箱為基本數(shù)據(jù)類型。

基本類型 占用空間(Byte) 表示范圍 包裝器類型
boolean 1/8 true、false Boolean
char 2 -128~127 Character
byte 1 -128~127 Byte
short 2 -2?15~2?15-1 Short
int 4 -2?31~2?31-1 Integer
long 8 -2?63~2?63-1 Long
float 4 -3.403E38~3.403E38 Float
double 8 -1.798E308~1.798E308 Double

以下感覺寫的比較好的博客:
Java自動(dòng)裝箱與拆箱及其陷阱
Java 的Integer、int與new Integer到底怎么回事?

String

Java的虛擬機(jī)在內(nèi)存中開辟出一塊單獨(dú)的區(qū)域,用來存儲(chǔ)字符串對(duì)象,這塊內(nèi)存區(qū)域被稱為字符串緩沖池。當(dāng)使用 String a = "abc" 這樣的語句進(jìn)行定義一個(gè)引用的時(shí)候,首先會(huì)在字符串緩沖池中查找是否已經(jīng)相同的對(duì)象,如果存在,那么就直接將這個(gè)對(duì)象的引用返回給a,如果不存在,則需要新建一個(gè)值為"abc"的對(duì)象,再將新的引用返回a。
String a = new String("abc");這樣的語句明確告訴JVM想要產(chǎn)生一個(gè)新的String對(duì)象,并且值為"abc",于是就在堆內(nèi)存中的某一個(gè)小角落開辟了一個(gè)新的String對(duì)象。

  • == ?在比較引用的情況下,會(huì)去比較兩個(gè)引用的內(nèi)存地址是否相等。
    String str1 = "abc";
    String str2 = "abc";
    System.out.println(str1 == str2);
    System.out.println(str1.equals(str2));
    String str2 = new String("abc");
    System.out.println(str1 == str2);
    System.out.println(str1.equals(str2));
以上代碼將會(huì)輸出
true
true
false
true
**第一個(gè)true:**因?yàn)樵趕tr2賦值之前,str1的賦值操作就已經(jīng)在內(nèi)存中創(chuàng)建了一個(gè)值為"abc"的對(duì)象了,然后str2將會(huì)與str1指向相同的地址。
**第二個(gè)true:**因?yàn)閌String`已經(jīng)重寫了`equals`方法:為了方便大家閱讀我貼出來,并且在注釋用進(jìn)行分析:
```
public boolean equals(Object anObject) {
//如果比較的對(duì)象與自身內(nèi)存地址相等的話
//就說明他兩指向的是同一個(gè)對(duì)象
//所以此時(shí)equals的返回值跟==的結(jié)果是一樣的。
if (this == anObject) {
    return true;
}
//當(dāng)比較的對(duì)象與自身的內(nèi)存地址不相等,并且
//比較的對(duì)象是String類型的時(shí)候
//將會(huì)執(zhí)行這個(gè)分支
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;
        //在這里循環(huán)遍歷兩個(gè)String中的char
        while (n-- != 0) {
            //只要有一個(gè)不相等,那么就會(huì)返回false
            if (v1[i] != v2[i])
                return false;
            i++;
        }
        return true;
    }
}
return false;

}
```

自定義類

public class Test {
    public static void main(String args[]){
        test();
    }

    public static void test(){
        A a = new A(1);
        A b = new A(1);
        System.out.println(a==b);
        System.out.println(a.equals(b));
    }
    static class A {
        private int a;
        public A(int a){
            this.a =a ;
        }
    }
}

這時(shí)候輸出的結(jié)果兩個(gè)都是false,因?yàn)锳類是Objcet的子類,在沒有重寫equals方法的時(shí)候,調(diào)用equals方法其實(shí)是調(diào)用Object的equals的方法,而Object類中的equals方法和“==”是一樣的,比較的還是內(nèi)存中的存放地址
Object的equals的源碼

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

重寫Object的equals方法(類似于String的equals方法)

public class Test {
    public static void main(String args[]){
        test();
    }

    public static void test(){
        A a = new A(1);
        A b = new A(1);
        System.out.println(a==b);
        System.out.println(a.equals(b));
    }
    static class A {
        private int a;
        public A(int a){
            this.a =a ;
        }
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (!(obj instanceof A)) {
                return false;
            }
            A other = (A) obj;
            return a==other.a;
        }
    }
}

這里返回值第一個(gè)是false,第二個(gè)是true

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,778評(píng)論 18 399
  • 【程序1】 題目:古典問題:有一對(duì)兔子,從出生后第3個(gè)月起每個(gè)月都生一對(duì)兔子,小兔子長到第三個(gè)月后每個(gè)月又生一對(duì)兔...
    葉總韓閱讀 5,167評(píng)論 0 41
  • Java經(jīng)典問題算法大全 /*【程序1】 題目:古典問題:有一對(duì)兔子,從出生后第3個(gè)月起每個(gè)月都生一對(duì)兔子,小兔子...
    趙宇_阿特奇閱讀 1,916評(píng)論 0 2
  • 一、 1、請(qǐng)用Java寫一個(gè)冒泡排序方法 【參考答案】 public static void Bubble(int...
    獨(dú)云閱讀 1,421評(píng)論 0 6
  • 我國是一個(gè)歷史悠久的國家,這種悠久不僅會(huì)影響城市的發(fā)展形態(tài),也會(huì)在城市的名字上留下深刻的烙印。縱觀國內(nèi)的城市,有些...
    史趣閱讀 814評(píng)論 0 0