<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Sunspl

    Hello,everyone,i am sun. 天道酬勤,笨鳥先飛.
    隨筆 - 47, 文章 - 0, 評論 - 24, 引用 - 0
    數(shù)據(jù)加載中……

    equals 與 ==

    初學(xué) Java 有段時間了,感覺似乎開始入了門,有了點兒感覺
    但是發(fā)現(xiàn)很多困惑和疑問而且均來自于最基礎(chǔ)的知識
    折騰了一陣子又查了查書,終于對 String 這個特殊的對象有了點感悟

    大家先來看看一段奇怪的程序:
    public class TestString {
        public static void main(String[] args) {
            String s1 = "Monday";
            String s2 = "Monday";
        }
    }
    這個程序真是簡單啊!可是有什么問題呢?

    1. 來自 String 的憂慮
    上面這段程序中,到底有幾個對象呢?
    可能很多人脫口而出:兩個,s1 和 s2
    為什么?
    String 是 final 類,它的值不可變。
    看起來似乎很有道理,那么來檢測一下吧,稍微改動一下程序
    就可以看到結(jié)果了:

    public class TestString {
        public static void main(String[] args) {
            String s1 = "Monday";
            String s2 = "Monday";
            if (s1 == s2)
                System.out.println("s1 == s2");
            else
                System.out.println("s1 != s2");
        }
    }
    呵呵,很多人都會說已經(jīng)不止兩個對象了
    編譯并運行程序,輸出:s1 == s2
    啊!
    為什么 s1 == s2 ?
    == 分明是在說:s1 與 s2 引用同一個 String 對象 -- "Monday"!

    2. 千變?nèi)f化的 String
    再稍微改動一下程序,會有更奇怪的發(fā)現(xiàn):
    public class TestString {
        public static void main(String[] args) {
            String s1 = "Monday";
            String s2 = new String("Monday");
            if (s1 == s2)
                System.out.println("s1 == s2");
            else
                System.out.println("s1 != s2");
            if (s1.equals(s2))
                System.out.println("s1 equals s2");
            else
                System.out.println("s1 not equals s2");
        }
    }
    我們將 s2 用 new 操作符創(chuàng)建
    程序輸出:
    s1 != s2
    s1 equals s2
    嗯,很明顯嘛
    s1 s2分別引用了兩個"Monday"String對象
    可是為什么兩段程序不一樣呢?

    3. 在 String 的游泳池中游泳
    哈哈,翻了翻書終于找到了答案:
    原來,程序在運行的時候會創(chuàng)建一個字符串緩沖池
    當(dāng)使用 s2 = "Monday" 這樣的表達(dá)是創(chuàng)建字符串的時候,程序首先會
    在這個String緩沖池中尋找相同值的對象,在第一個程序中,s1先被
    放到了池中,所以在s2被創(chuàng)建的時候,程序找到了具有相同值的 s1
    將 s2 引用 s1 所引用的對象"Monday"

    第二段程序中,使用了 new 操作符,他明白的告訴程序:
    “我要一個新的!不要舊的!”與是一個新的"Monday"Sting對象被創(chuàng)
    建在內(nèi)存中。他們的值相同,但是位置不同,一個在池中游泳
    一個在岸邊休息。哎呀,真是資源浪費,明明是一樣的非要分開做什么呢?

    4. 繼續(xù)潛水
    再次更改程序:
    public class TestString {
        public static void main(String[] args) {
            String s1 = "Monday";
            String s2 = new String("Monday");
            s2 = s2.intern();
            if (s1 == s2)
                System.out.println("s1 == s2");
            else
                System.out.println("s1 != s2");
            if (s1.equals(s2))
                System.out.println("s1 equals s2");
            else
                System.out.println("s1 not equals s2");
        }
    }
    這次加入:s2 = s2.intern();
    哇!程序輸出:
    s1 == s2
    s1 equals s2
    原來,程序新建了 s2 之后,又用intern()把他打翻在了池里
    哈哈,這次 s2 和 s1 有引用了同樣的對象了
    我們成功的減少了內(nèi)存的占用

    5. == 與 equals() 的爭斗
    String 是個對象,要對比兩個不同的String對象的值是否相同
    明顯的要用到 equals() 這個方法
    可是如果程序里面有那么多的String對象,有那么多次的要用到 equals ,
    哦,天哪,真慢啊
    更好的辦法:
    把所有的String都intern()到緩沖池去吧
    最好在用到new的時候就進(jìn)行這個操作
    String s2 = new String("Monday").intern();
    嗯,大家都在水池里泡著了嗎?哈哈
    現(xiàn)在我可以無所顧忌的用 == 來比較 String 對象的值了
    真是爽啊,又快又方便!
    關(guān)于String :)
    String 啊 String ,讓我說你什么好呢?
    你為我們 Java 程序員帶來所有的困擾還不夠嗎?
    看看 String 這一次又怎么鬧事兒吧

    1. 回顧一下壞脾氣的 String 老弟

    例程1:
    class Str {
        public static void main(String[] args) {
            String s = "Hi!";
            String t = "Hi!";
            if (s == t)
                System.out.println("equals");
            else
                System.out.println("not equals");
        }
    }

    程序輸出什么呢?
    如果看客們看過我的《來自 String 的困惑》之一
    相信你很快會做出正確的判斷:
    程序輸出:equals

    2. 哦,天哪,它又在攪混水了

    例程2:
    class Str {
        public static void main(String[] args) {
            String s = "HELLO";
            String t = s.toUpperCase();
            if (s == t)
                System.out.println("equals");
            else
                System.out.println("not equals");
        }
    }
    那么這個程序有輸出什么呢?
    慎重!再慎重!不要被 String 這個迷亂的家伙所迷惑!
    它輸出:equals
    WHY!!!

    把程序簡單的更改一下:
    class Str2 {
        public static void main(String[] args) {
            String s = "Hello";
            String t = s.toUpperCase();
            if (s == t)
                System.out.println("equals");
            else
                System.out.println("not equals");
        }
    }
    你可能會說:不是一樣嗎?
    不!千真萬確的,不一樣!這一次輸出:not equals

    Oh MyGOD!!!
    誰來教訓(xùn)一下這個 String 啊!

    3. 你了解你的馬嗎?
    “要馴服脫韁的野馬,就要了解它的秉性”牛仔們說道。
    你了解 String 嗎?

    解讀 String 的 API ,可以看到:
    toUpperCase() 和 toLowerCase() 方法返回一個新的String對象,
    它將原字符串表示字符串的大寫或小寫形勢;
    但是要注意:如果原字符串本身就是大寫形式或小寫形式,那么返回原始對象。
    這就是為什么第二個程序中 s 和 t 糾纏不清的緣故

    對待這個淘氣的、屢教不改的 String ,似乎沒有更好的辦法了
    讓我們解剖它,看看它到底有什么結(jié)構(gòu)吧:

    (1) charAt(int n) 返回字符串內(nèi)n位置的字符,第一個字符位置為0,
    最后一個字符的位置為length()-1,訪問錯誤的位置會扔出一塊大磚頭:
    StringIndexOutOfBoundsException 真夠大的

    (2) concat(String str) 在原對象之后連接一個 str ,但是返回一個新的 String 對象

    (3) EqualsIgnoreCase(String str) 忽略大小寫的 equals 方法
    這個方法的實質(zhì)是首先調(diào)用靜態(tài)字符方法toUpperCase() 或者 toLowerCase()
    將對比的兩個字符轉(zhuǎn)換,然后進(jìn)行 == 運算

    (4) trim() 返回一個新的對象,它將原對象的開頭和結(jié)尾的空白字符切掉
    同樣的,如果結(jié)果與原對象沒有差別,則返回原對象

    (5) toString() String 類也有 toString() 方法嗎?
    真是一個有趣的問題,可是如果沒有它,你的 String 對象說不定真的不能用在
    System.out.println() 里面啊
    小心,它返回對象自己

    String 類還有很多其他方法,掌握他們會帶來很多方便
    也會有很多困惑,所以堅持原則,是最關(guān)鍵的

    4. 我想買一匹更好的馬
    來購買更馴服溫和的 String 的小弟 StringBuffer 吧
    這時候會有人反對:它很好用,它效率很高,它怎么能夠是小弟呢?
    很簡單,它的交互功能要比 String 少,如果你要編輯字符串
    它并不方便,你會對它失望
    但這不意味著它不強(qiáng)大
    public final class String implements Serializable, Comparable, CharSequence
    public final class StringBuffer implements Serializable, CharSequence
    很明顯的,小弟少了一些東東,不過這不會干擾它的前途

    StringBuffer 不是由 String 繼承來的
    不過要注意兄弟它也是 final 啊,本是同根生

    看看他的方法吧,這么多穩(wěn)定可靠的方法,用起來比頑皮的 String 要有效率的多
    ?br /> Java 為需要改變的字符串對象提供了獨立的 StringBuffer 類
    它的實例不可變(final),之所以要把他們分開
    是因為,字符串的修改要求系統(tǒng)的開銷量增大,
    占用更多的空間也更復(fù)雜,相信當(dāng)有10000人擠在一個狹小的游泳池里游泳
    而岸邊又有10000人等待進(jìn)入游泳池而焦急上火
    又有10000人在旁邊看熱鬧的時候,你這個 String 游泳池的管理員也會焦頭爛額

    在你無需改變字符串的情況下,簡單的 String 類就足夠你使喚的了,
    而當(dāng)要頻繁的更改字符串的內(nèi)容的時候,就要借助于宰相肚里能撐船的
    StringBuffer 了

    5. 宰相肚里能撐船
    (1) length() 與 capacity()
    String 中的 length() 返回字符串的長度
    兄弟 StringBuffer 也是如此,他們都由對象包含的字符長度決定

    capacity()呢?
    public class TestCapacity {
        public static void main(String[] args){
            StringBuffer buf = new StringBuffer("it was the age of wisdom,");
            System.out.println("buf = " + buf);
            System.out.println("buf.length() = " + buf.length());
            System.out.println("buf.capacity() = " + buf.capacity());
            String str = buf.toString();
            System.out.println("str = " + str);
            System.out.println("str.length() = " + str.length());
            buf.append(" " + str.substring(0,18)).append("foolishness,");
            System.out.println("buf = " + buf);
            System.out.println("buf.length() = " + buf.length());
            System.out.println("buf.capacity() = " + buf.capacity());
            System.out.println("str = " + str);
        }
    }
    程序輸出:
    buf = it was the age of wisdom.
    buf.length() = 25
    buf.capacity() = 41
    str = it was the age of wisdom
    str.length() = 25
    buf = it was the age of wisdom, it was the age of foolishness,
    buf.length() = 56
    buf.capacity() = 84
    str = it was the age of wisdom,

    可以看到,在內(nèi)容更改之后,capacity也隨之改變了
    長度隨著向字符串添加字符而增加
    而容量只是在新的長度超過了現(xiàn)在的容量之后才增加
    StringBuffer 的容量在操作系統(tǒng)需要的時候是自動改變的
    程序員們對capacity所能夠做的僅僅是可以在初始化 StringBuffer對象的時候
    以上片斷引用自http://bbs.blueidea.com/viewthread.php?tid=945875&page=###
    解釋得比較形象和經(jīng)典。具體的比較,要親自動手運行一下程序才行,如下為網(wǎng)上找到的專門研究equals和==的關(guān)系的程序,相信可從中體會出他們的深刻不同:
    String s1 = null;
    String s2 = null;
    System.out.println(s1==s2);//true
    //System.out.println(s1.equals(s2));//NullPointerException
    s1 = s2;
    System.out.println(s1==s2);//true
    //System.out.println(s1.equals(s2));//NullPointerException
    System.out.println("***1***");

    s1 = null;
    s2 = "";
    System.out.println(s1==s2);//false
    //System.out.println(s1.equals(s2));//NullPointerException
    s1 = s2;
    System.out.println(s1==s2);//true
    System.out.println(s1.equals(s2));//true
    System.out.println("***2***");

    s1 = "";
    s2 = null;
    System.out.println(s1==s2);//false
    System.out.println(s1.equals(s2));//false
    s1 = s2;
    System.out.println(s1==s2);//true
    //System.out.println(s1.equals(s2));//NullPointerException
    System.out.println("***3***");

    s1 = "";
    s2 = "";
    System.out.println(s1==s2);//true
    System.out.println(s1.equals(s2));//true
    s1 = s2;
    System.out.println(s1==s2);//true
    System.out.println(s1.equals(s2));//true
    System.out.println("***4***");
    s1 = new String("");
    s2 = new String("");
    System.out.println(s1==s2);//false
    System.out.println(s1.equals(s2));//true
    s1 = s2;
    System.out.println(s1==s2);//true
    System.out.println(s1.equals(s2));//true
    System.out.println("***5***");

    s1 = "null";
    s2 = "null";
    System.out.println(s1==s2);//ture
    System.out.println(s1.equals(s2));//true
    s1 = s2;
    System.out.println(s1==s2);//true
    System.out.println(s1.equals(s2));//true
    System.out.println("***6***");
    s1 = new String("null");
    s2 = new String("null");
    System.out.println(s1==s2);//flase
    System.out.println(s1.equals(s2));//true
    s1 = s2;
    System.out.println(s1==s2);//true
    System.out.println(s1.equals(s2));//true
    System.out.println("***7***");

    s1 = "abc";
    s2 = "abc";
    System.out.println(s1==s2);//ture
    System.out.println(s1.equals(s2));//true
    s1 = s2;
    System.out.println(s1==s2);//true
    System.out.println(s1.equals(s2));//true
    System.out.println("***8***");
    s1 = new String("abc");
    s2 = new String("abc");
    System.out.println(s1==s2);//false
    System.out.println(s1.equals(s2));//true
    s1 = s2;
    System.out.println(s1==s2);//true
    System.out.println(s1.equals(s2));//true
    System.out.println("***9***");

    總結(jié):   多數(shù)情況下這兩者的區(qū)別就是究竟是對對象的引用進(jìn)行比較還是對對象的值進(jìn)行比較(其他特殊情況此處不予考慮)。==操作符是比較的對象的引用而不是對象的值。

    但在最初的Object對象中的equals方法與==操作符完成功能是相同的。
    源碼:
    java.lang.Object.equals()方法:
    -------------------------------------------------------------
    public boolean equalss(Object obj) {
     return (this = = obj);
        }
    -------------------------------------------------------------
    jdk文檔中給出如下解釋:
    -------------------------------------------------------------
    The equalss method implements an equivalence relation:
    · It is reflexive: for any reference value x, x.equalss(x) should return true.
    · It is symmetric: for any reference values x and y, x.equalss(y) should return true if and only if y.equalss(x) returns true.
    · It is transitive: for any reference values x, y, and z, if x.equalss(y) returns true and y.equalss(z) returns true, then x.equalss(z) should return true.
    · It is consistent: for any reference values x and y, multiple invocations of x.equalss(y) consistently return true or consistently return false, provided no information used in equalss comparisons on the object is modified.
    · For any non-null reference value x, x.equalss(null) should return false.
    The equalss method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any reference values x and y, this method returns true if and only if x and y refer to the same object (x==y has the value true).
    Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equals objects must have equals hash codes.
    -------------------------------------------------------------

    對于String類的equals方法是對什么內(nèi)容進(jìn)行比較的呢?下面我們來看它的代碼和注釋:
    源代碼:
    -------------------------------------------------------------
    public boolean equals(Object anObject) {
     if (this == anObject) {
         return true;
     }
     if (anObject instanceof String) {
         String anotherString = (String)anObject;
         int n = count;
         if (n == anotherString.count) {
      char v1[] = value;
      char v2[] = anotherString.value;
      int i = offset;
      int j = anotherString.offset;
      while (n-- != 0) {
          if (v1[i++] != v2[j++])
       return false;
      }
      return true;
         }
     }
     return false;
        }


    -------------------------------------------------------------
    此方法的注釋為:
    -------------------------------------------------------------
    Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
    -------------------------------------------------------------
    由上面的代碼和注釋可以得到String類的equal方法是對對象的值進(jìn)行比較。
    根據(jù)以上的討論可以得出結(jié)論:equal方法和==操作符是否存在區(qū)別要個別對待,要根據(jù)equal的每個實現(xiàn)情況來具體判斷。

     

    posted on 2008-06-11 22:36 JavaSuns 閱讀(735) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲中文字幕久久精品无码喷水| a级毛片无码免费真人| 亚洲国产一区视频| WWW亚洲色大成网络.COM| 思思99re66在线精品免费观看| 亚洲专区一路线二| 日韩精品成人无码专区免费| 亚洲精品123区在线观看| 久久久久免费看黄A片APP | 免费国产在线观看老王影院| 在线观看亚洲免费| jjzz亚洲亚洲女人| XXX2高清在线观看免费视频| 在线亚洲97se亚洲综合在线| 国产精品99精品久久免费| 亚洲VA中文字幕不卡无码| 亚洲毛片在线免费观看| 亚洲人成色777777精品| 亚洲精品国产成人影院| 国产啪精品视频网站免费尤物| 亚洲天堂视频在线观看| 两性刺激生活片免费视频| 久久亚洲精品无码gv| 亚洲精品无码99在线观看| 日本高清高色视频免费| 亚洲AV日韩综合一区尤物| 亚洲精品WWW久久久久久| 免费国产成人午夜在线观看| 亚洲成a人片毛片在线| 日本不卡视频免费| 国产免费无码一区二区| 33333在线亚洲| 亚洲婷婷国产精品电影人久久| 久久国产精品免费观看| 在线亚洲高清揄拍自拍一品区| 亚洲Aⅴ无码专区在线观看q| 国产黄色免费网站| 免费观看四虎精品成人| 亚洲精品自产拍在线观看动漫| 精品国产精品久久一区免费式| 亚洲福利在线观看|