Java基礎之String中equals,聲明方式,等大總結

來源:互聯網
上載者:User

Java基礎之String中equals,聲明方式,等大總結

 

無論你是一個編程新手還是老手,提到String你肯定感覺特別熟悉,因為String類我們在學習java基礎的時候就已經學過,但是String類型有我們想象的那麼簡單嗎?其實不然,String類型的知識點還是比較多的。今天就和大家來一起討論一下,關於String的一些容易讓人疑惑的地方,廢話不多說進入正題。。。如有謬誤請批評指正,如果有疑問請留言。我會在第一時間修改或回答

通過本篇部落格你將學到以下知識

①==和equals的區別,String a=abc和String a=new String(abc)的堆記憶體和棧記憶體的變化

②String a=abc和String a=new String(abc)兩種聲明方式的區別

③abc.equals(abc)和a.equals(abc)的區別,從源碼分析為什麼abc.euqals(str)可以避免null 指標
④String對象的值是不能修改的,為啥可以重新賦值,並且改變
⑤String a;和String a = null,String a =的區別
⑥String s1 = new String(s1) ;String s2 = new String(s1) ;總共建立了幾個對象?
1、==和equals的區別,String a=abc和String a=new String(abc)的堆記憶體和棧記憶體的變化
我們首先來看一段代碼
public class StringDemo {public static void main(String[] args) {String str1 = hello;String str2 = new String(hello);String str3 = str2;System.out.println(str1==str2:+(str1==str2));System.out.println(str1==str2:+(str1==str3));System.out.println(str1==str2:+(str2==str3));}}
列印結果如下
why?為什麼會這樣列印呢?上面的例子str1、str2、str3的內容都是一樣的但比較的結果卻是有的相等,有的不相等,這是為啥?首先看一張記憶體上述的記憶體配置圖
可以清楚的發現每個String對象的內容實際是儲存到堆記憶體中的,而且堆中的內容是相等的。但是對於str1和str2來說所指向的地址堆記憶體位址是不等的,所以儘管內容是相等的,但是地址值是不相等的,“==”是用來進行數值比較的,所以str1和str2比較不相等,因為str2和str3指向同一個記憶體位址所以str2和str3是相等的。所以“==”是用來進行地址值比較的。 那麼怎麼判斷兩個字串的內容是否相等呢?我們先看個例子
public class StringDemo {public static void main(String[] args) {String str1 = hello;String str2 = new String(hello);String str3 = str2;System.out.println(str1 equals str2:+(str1.equals(str2)));System.out.println(str1 equals str2:+(str1.equals(str3)));System.out.println(str1 equals str2:+(str2.equals(str3)));}}
運行結果如下
因為equals方法的作用是將內容進行比較,所以此處的返回結果都為true。 總結以上兩個例子我們可以總結出==和equals的區別是:“==”是用來進行數值比較的,在String中用“==”進行地址值的比較,而equals比較的是String的內容。
2.兩種聲明方式的區別 首先必須明白的一點就是一個字串就是String的匿名對象,為什麼這樣說呢?我們可以通過hello.equals(hello)的列印結果為true進行驗證,因為“hello”可以通過“hello”.equals()直接調用String中的方法,因此對於String str1=hello;實際上就是把一個在堆記憶體中開闢好的堆記憶體空間的使用權給了str1對象,而使用這種方法還有另外一個好處,就是如果一個字串已經被一個名稱所引用,則以後再有相同的字串聲明時,就不會再重新開闢空間,而繼續使用已經開闢好的堆記憶體,啥意思?我們通過一個例子來進行說明,這個例子的代碼如下
public class StringDemo {public static void main(String[] args) {String str1 = hello;String str2 = hello;String str3 = hello;System.out.println(str1==str2: + (str1 == str2));System.out.println(str1==str3: + (str1 == str3));System.out.println(str2==str3: + (str2 == str3));}}
列印結果如下
咦,這是啥子情況啊?上面我們剛得出結論==在String中比較的是地址值,為什麼列印結果都是true呢?其實這是java中一種共用設計,這種設計思路是,在java中形成一個對象池,在這個池中儲存多個對象,新執行個體化的對象如果已經在池中定義了則不再重新定義,而從池中取出繼續使用。String採用了這種設計,在Java運行環境中有一個字串池,由String類維護。執行語句String str1=hello時,首先查看字串池中是否存在字串hello,如果存在則直接將hello賦給str1,如果不存在則先在字串池中建立一個字串hello,然後再將其賦給str1。執行語句String str=new String(hello)時,不管字串池中是否存在字串hello,直接建立一個字串hello(注意:建立的字串hello不是在字串池中),然後將其付給str。前一語句的效率高,後一語句的效率低,因為建立字串佔用記憶體空間。String str = new String()建立了一個Null 字元串,與String str=new String()相同。
我們總結一下:單獨是用引號建立的字串都是常量,編譯期就已經確定好儲存到String池中,使用new String()建立的對象會儲存到堆記憶體(head)中是運行時期建立的。
通過以上的兩種實現方式的比較可以知道哪種方式更合適,對於字串的操作直接採用直接賦值的方式完成,而不要採用構造方法傳遞字串的方式完成,這樣可以避免產生垃圾空間。
3.字串的內容不可變 字串的內容不可變?可能有的說你別在這忽悠我了,咋可能這不是胡扯嗎?先別急,我們同樣先看個例子代碼如下
public class StringDemo {public static void main(String[] args) {String str=hello;str=str+ world!;System.out.println(str=+str);}}
列印結果
可能有的人會說你看這不是變了嗎?開始是hello後面是hello world!。從程式運行結果發現,String對象的內容確實已經修改了,但是內容真的修改了嗎?下面通過記憶體的分配圖說明字串內容不可更改的含義
從可以清楚的發現,一個String對象內容的改變實際上時通過記憶體位址的斷開-串連變化完成的,而本身字串中的內容並沒有任何的變化。
4.abc.equals(str)和str.equals(abc)的區別,從源碼分析為什麼abc.euqals(str)可以避免null 指標
我們應該都聽說過abc.equals(str)這種寫法可以避免null 指標,為啥?可能有好多人經常這樣寫,但是不明白原理是啥?我們從一個例子說起
public class StringDemo {public static void main(String[] args) {String str1 = hello;String str2 = null;System.out.println(str1.equals(str2));}}

再來看段代碼
public class StringDemo {public static void main(String[] args) {String str1 = hello;String str2 = null;System.out.println(str2.equals(str1));}}
和上面的代碼唯一不同的是上面是str1.equals(str2),這裡是str2.equals(str1),我們看看列印結果會是啥樣。
我曰它大爺,報null 指標,為啥嘞?為啥st1.equals(str2)會列印false,而str2.equals(str1)就報null 指標,這不科學啊。要想知道原因唯獨源碼最具說服力,我們來看看String類中的equals源碼不就行了,好咱們去看看唄String類中equals的源碼如下
/**      * Compares this string to the specified object.  The result is {@code      * true} if and only if the argument is not {@code null} and is a {@code      * String} object that represents the same sequence of characters as this      * object.      *      * @param  anObject      *         The object to compare this {@code String} against      *      * @return  {@code true} if the given object represents a {@code String}      *          equivalent to this string, {@code false} otherwise      *      * @see  #compareTo(String)      * @see  #equalsIgnoreCase(String)      */      public boolean equals(Object anObject) {      //判斷是否是和自己比較        if (this == anObject) {              return true;          }          //判斷傳過來的anObject是否是String類型的執行個體        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類型的執行個體,注意 instanceof這個關鍵字的作用就是判斷一個對象是哪個類的執行個體,注意這裡是執行個體,我們直接String str2=null,此時str2並不是String類型的執行個體,不信你可以去驗證,因為String str2=null,申明一個String類型的str2,同時在記憶體裡申請了一個地址,但是該地址不指向任何引用地址,所以在執行這個判斷時直接跳出if語句返回false。所以就不會報null 指標啦啦啦。。。
5.String a;和String a = null,String a =的區別
String a;申明一個string類型的 a,即沒有在申請記憶體位址,更沒有在記憶體任何指向引用地址;

String a = null ;申明一個string類型的 a,同時在記憶體裡申請了一個地址,但是該地址不指向任何引用地址;

String a = ;申明一個string類型的 a,既在記憶體裡申請了地址,該地址又指向一個引用該字串的引用地址;
string a=null,String b=hello; system.out.println(a+b);輸出nullhello;
6.String s1 = new String(s1) ;String s2 = new String(s1) ;總共建立了幾個對象? 對於這個問題,通過上面的分析其實也不難理解,首先String s1 = new String(s1),我們看到(s1),此時s1作為常量被讀入,所以會在String池中建立一個對象,之後又看到了new此時會在堆記憶體(head)中再建立一個對象,所以執行String s1=new String(s1)時建立了兩個對象,而接著執行String s2=new String(s1)時,(s1)也會被作為常量讀入,但是由於String池中已經有了s1所以這一次不會在String池中建立對象了,而執行new時是必須要建立對象的,所以執行String s2=new String(s1);時建立了一個對象。看下面兩段代碼: 第一段代碼: String s1 = new String(s1); //建立二個對象,一個引用
String s2 = new String(s1); //建立一個對象,並且以後每執行一次建立一個對象,一個引用
第二段代碼: String s3 = xyz; //建立一個對象,一個引用
String s4 = xyz; //不建立對象,只是建立一個新的引用
關於String類型的分析到這裡就結束了,下班後加了會班,完成了此部落格,如果你覺著對你有用,我不介意你留言頂一個,哈哈,今天是周五,祝大家周末愉快啊。。。。  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.