<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
    數據加載中……

    equals 與 ==

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

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

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

    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");
        }
    }
    呵呵,很多人都會說已經不止兩個對象了
    編譯并運行程序,輸出:s1 == s2
    啊!
    為什么 s1 == s2 ?
    == 分明是在說:s1 與 s2 引用同一個 String 對象 -- "Monday"!

    2. 千變萬化的 String
    再稍微改動一下程序,會有更奇怪的發現:
    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 操作符創建
    程序輸出:
    s1 != s2
    s1 equals s2
    嗯,很明顯嘛
    s1 s2分別引用了兩個"Monday"String對象
    可是為什么兩段程序不一樣呢?

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

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

    4. 繼續潛水
    再次更改程序:
    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 有引用了同樣的對象了
    我們成功的減少了內存的占用

    5. == 與 equals() 的爭斗
    String 是個對象,要對比兩個不同的String對象的值是否相同
    明顯的要用到 equals() 這個方法
    可是如果程序里面有那么多的String對象,有那么多次的要用到 equals ,
    哦,天哪,真慢啊
    更好的辦法:
    把所有的String都intern()到緩沖池去吧
    最好在用到new的時候就進行這個操作
    String s2 = new String("Monday").intern();
    嗯,大家都在水池里泡著了嗎?哈哈
    現在我可以無所顧忌的用 == 來比較 String 對象的值了
    真是爽啊,又快又方便!
    關于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!!!
    誰來教訓一下這個 String 啊!

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

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

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

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

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

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

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

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

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

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

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

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

    在你無需改變字符串的情況下,簡單的 String 類就足夠你使喚的了,
    而當要頻繁的更改字符串的內容的時候,就要借助于宰相肚里能撐船的
    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,

    可以看到,在內容更改之后,capacity也隨之改變了
    長度隨著向字符串添加字符而增加
    而容量只是在新的長度超過了現在的容量之后才增加
    StringBuffer 的容量在操作系統需要的時候是自動改變的
    程序員們對capacity所能夠做的僅僅是可以在初始化 StringBuffer對象的時候
    以上片斷引用自http://bbs.blueidea.com/viewthread.php?tid=945875&page=###
    解釋得比較形象和經典。具體的比較,要親自動手運行一下程序才行,如下為網上找到的專門研究equals和==的關系的程序,相信可從中體會出他們的深刻不同:
    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***");

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

    但在最初的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方法是對什么內容進行比較的呢?下面我們來看它的代碼和注釋:
    源代碼:
    -------------------------------------------------------------
    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方法是對對象的值進行比較。
    根據以上的討論可以得出結論:equal方法和==操作符是否存在區別要個別對待,要根據equal的每個實現情況來具體判斷。

     

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


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


    網站導航:
     
    主站蜘蛛池模板: 亚洲伊人久久综合影院| 久久久久久国产精品免费免费| 亚洲?v无码国产在丝袜线观看| 亚洲国产精品一区二区三区在线观看| 久久精品无码专区免费青青| 亚洲AV无码久久寂寞少妇| 日本高清不卡aⅴ免费网站| 国产亚洲精品岁国产微拍精品| 国产精品内射视频免费| 亚洲精品无码久久一线| 国产一区二区免费视频| 久久亚洲精品成人777大小说| 成人片黄网站色大片免费观看APP| 亚洲一区二区三区影院 | 亚洲AV无码乱码在线观看富二代| 国产成人无码免费网站| 亚洲精品国产字幕久久不卡 | 13一14周岁毛片免费| 亚洲性69影院在线观看| www.999精品视频观看免费| 亚洲熟妇丰满xxxxx| 国产精品无码免费视频二三区| 免费激情网站国产高清第一页| 亚洲色一色噜一噜噜噜| 免费在线看黄的网站| 亚洲国产亚洲综合在线尤物| 最近中文字幕免费mv视频8| 日本一区二区三区免费高清在线 | 伊人久久综在合线亚洲2019| 免费看黄视频网站| 粉色视频在线观看www免费| 亚洲乱码国产一区三区| 青娱乐免费在线视频| 久久精品国产亚洲AV| 精品亚洲综合在线第一区| 日韩版码免费福利视频| 九九全国免费视频| 亚洲人成人77777网站不卡| 免费**毛片在线播放直播| 亚在线观看免费视频入口| 亚洲一卡一卡二新区无人区|