JAVA中特殊類String類

實例化方式

既然是一個類,我們知道,一般的類在實例化的時候都是使用傳統實例化方式,new一個對象,而String類中提供兩種實例化方式:

  • 傳統方式
String str = new String("Hello Bit") ;
  • 直接賦值
String str = "Hello Bit" ; // str是一個對象,那麼"Hello Bit" 就應該保存在堆內存中

字符串比較

我們在比較基本數據類型數值時,大多使用’= =’,那麼比較字符串是否也可以用’= ='進行比較呢?我們不妨測試一下,如下代碼:

String str1 = "Hello" ;
String str = new String("Hello") ;
System.out.println(str1==str); // false

結果表明:兩個字符串內容是相同的課時用‘==’比較出來的結果卻是false,這是什麼原因呢?我們可以來看一下它們在內存中的存放情況,如下圖:
在這裏插入圖片描述
在這裏插入圖片描述
我們發現,這兩個字符串並不在同一個內存塊中,那麼比較的結果也就不同了。因此,我們總結出‘= =’比較的情況:

== 本身是進行數值比較的,如果用於對象比較,那麼所比較的就應該是兩個對象所保存的內存地址數值比較,而並沒有比較對象的內容。

那麼我們要向比較兩個字符串的內容而不是數值呢?應該如何比較呢,這時候String類就提供了一個equals方法,我們可以使用equals比較兩個字符串的內容,如下:

String str1 = "Hello" ;
String str = new String("Hello") ;
System.out.println(str1.equals(str));//true

通過以上比較,我們可以得出以下結論:

在String類中==和equals的區別如下:

  1. ”==”:進行的數值比較,比較的是兩個字符串對象的內存地址數值。
  2. “equals()”:可以進行字符串內容的比較

String類的匿名對象

在java中,本身是沒有提供字符串常量的概念的,所有用雙引號引起來的字符串的內容本質上來講其實都是String類的匿名對象。

String str1 = "Hello" ;
String str = new String("Hello") ;
System.out.println(str1.equals(str));//true
System.out.println("Hello".equals(str));//true

從結果中可以看出:”String str = ”hello““,本質上就是將一個匿名的String類對象設置有名字,而且匿名對象一定保存在堆內存中。
在這裏需要注意的是在日後的開發過程之中,如果要判斷用戶輸入的字符串是否等同於特定字符串,一定要將特定字符串寫在前面。
我們觀察以下兩個結果:

        String str = new String("Hello") ;
        System.out.println("Hello".equals(str));//true
        System.out.println(str.equals("hello"));//false

爲什麼一定要將特定字符串寫在前面呢?這是因爲,如果將變量寫在前面,倘若變量爲null的話,就會造成null引用equals方法導致空指針異常,所以爲了安全起見,在比較的時候一定要將特定字符串寫在前面。

實例化區別

那麼這兩種實例化方式有什麼區別呢?
我們看一段代碼:

String str1 = "hello" ;
String str2 = "hello" ;
String str3 = "hello" ;
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true
System.out.println(str2 == str3); // true

看到結果你是否吃了一驚呢?怎麼又是true了?其實仔細觀察,你就會發現這個和上面的代碼的區別,這三個比較都是直接賦值的,而之前的false是傳統的賦值。那麼這兩種賦值方式有什麼區別呢?我們看一看在內存中情況:
在這裏插入圖片描述
我們發現,這三個字符串在內存佔同一塊內存。

在JVM底層實際上會自動維護一個對象池(字符串對象池),如果現在採用了直接賦值的模式進行String類的對象
實例化操作,那麼該實例化對象(字符串內容)將自動保存到這個對象池之中。如果下次繼續使用直接賦值的模式
聲明String類對象,此時對象池之中如若有指定內容,將直接進行引用;如若沒有,則開闢新的字符串對象而後將
其保存在對象池之中以供下次使用
所謂的對象池就是一個對象數組(目的就是減少開銷)

而傳統的實例化方式,在內存中總是要開闢新的空間,例如:
在這裏插入圖片描述
我們觀察到,先是匿名對象“hello”在對象池中,然後新開闢的空間,並賦值,原來的匿名對象那塊內存會有垃圾空間GC回收,至於什麼時候回收,怎樣回收,我們都是不知道的。

// 該字符串常量並沒有保存在對象池之中
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2); // false

那麼在String類中提供有方法入池操作 public String intern(),例如:

String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2); // true

面試題:請解釋String類中兩種對象實例化的區別:

  1. 直接賦值:只會開闢一塊堆內存空間,並且該字符串對象可以自動保存在對象池中以供下次使用。
  2. 構造方法:會開闢兩塊堆內存空間,其中一塊成爲垃圾空間,不會自動保存在對象池中,可以使用intern()方法手工入池。

字符串不可變更

在定義字符串常量時,它的內容是不可改變的:

String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str); // hello world!!!

這裏的變更不是字符串常量的變更,而是字符串對象的變更。
在這裏插入圖片描述
可以發現字符串上沒有發生任何變化,但是字符串對象的引用一直在改變,而且會形成大量的垃圾空間。
通過以上所有,我們有以下三個原則:

  1. 字符串使用就採用直接賦值。
  2. 字符串比較就使用equals()實現。
  3. 字符串別改變太多。

字符與字符串

在String類中提供了很多方法可以實現字符與字符串之間的相互轉化,如下:
在這裏插入圖片描述

字節與字符串

字節常用於數據傳輸以及編碼轉換的處理之中,在String中提供有對字節的支持,如下:
在這裏插入圖片描述
除此之外String中海油很多常用的而方法,這裏不一一列舉。可以查看相關API文檔。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章