JavaRush /Java Blog /Random-TW /翻譯:在 Java 中建立 String 物件 - 使用「」還是建構子?
FellowSparrow
等級 12
Lvov

翻譯:在 Java 中建立 String 物件 - 使用「」還是建構子?

在 Random-TW 群組發布
原文:使用「」還是建構子來建立Java字串?作者:X Wang 翻譯:在 Java 中建立字串物件 - 用法在 Java 中,可以使用兩種方法建立字串:
String x = "abc";
String y = new String("abc");
使用雙引號和使用建構函數有什麼不同?

1. 雙引號與雙引號 建構函數

這個問題可以透過兩個簡單的例子來回答。範例1:
String a = "abcd";
String b = "abcd";
System.out.println(a == b);  // True
System.out.println(a.equals(b)); // True
a==btrue 是因為它們ab引用同一個物件 - 在方法區域中聲明為文字(下面的字串文字)的字串(我們建議讀者參考我們資源上的原始程式碼:了解 Java 的 Top 8 圖,圖 8)。當相同的字串文字被創建多次時,記憶體中僅儲存該字串的副本,即它的一個實例(在我們的例子中為「abcd」)。這稱為“字串實習”。所有在編譯時處理的字串常數都會自動駐留在 Java 中。範例2:
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d);  // False
System.out.println(c.equals(d)); // True
c==dfalse,因為c它們d引用記憶體中(堆上)的兩個不同物件。不同的物件總是有不同的引用。此圖說明了上述兩種情況: 翻譯:在 Java 中建立字串物件 - 用法

2. 程式執行期間​​插入字串

作者感謝 LukasEder(下面的評論是他的): 字串駐留也可能在程式執行期間​​發生,即使使用建構函式建立兩個字串:
String c = new String("abcd").intern();
String d = new String("abcd").intern();
System.out.println(c == d);  // Now true
System.out.println(c.equals(d)); // True

3.什麼時候使用雙引號,什麼時候使用建構函數

由於文字“abcd”始終是 String 類型,因此使用建構函數將建立額外的不必要的物件。因此,如果您只需要建立一個字串,則應使用雙引號。如果您確實需要在堆上建立一個新對象,則應該使用建構函式。此處顯示了用例(原始) 。(我在下面提供了翻譯後的文本。但我仍然強烈建議您熟悉此連結中評論者的程式碼。)

JDK 6 和 JDK 7 中的 substring() 方法

JDK 6 和 JDK 7 中的 substring() 方法By X Wang JDK 6 和 JDK 7 中的方法substring(int beginIndex, int endIndex)則有所不同。了解這些差異可以幫助您更好地使用此方法。為了方便閱讀,以下substring()我們將指完整的文法,即 substring(int beginIndex, int endIndex)

1. substring() 的作用是什麼?

此方法substring(int beginIndex, int endIndex)傳回以字元 number 開頭beginIndex並以字元 number 結尾的字串endIndex-1
String x = "abcdef";
x = x.substring(1,3);
System.out.println(x);
輸出:
bc

2. 呼叫 substring() 時會發生什麼事?

您可能知道,由於不變性x,當 的結果分配給 x 時x.substring(1,3)x它指向一個全新的行(見圖): 翻譯:在 Java 中建立字串物件 - 用法但是,該圖並不完全正確;它沒有展示堆中實際發生的情況。substring()在 JDK 6 和 JDK 7 中, 呼叫時實際發生的情況有所不同。

3. JDK 6中的substring()

數組類型支援字串類型char。在 JDK 6 中,此類別String包含 3 個欄位:char value[]int offsetint count。它們用於儲存實際的字元數組、數組中第一個字元的索引、行中的字元數。當呼叫該方法時substring(),它會建立一個新行,但變數的值仍然指向堆上的相同數組。兩個字串之間的差異在於它們的字元數和陣列中起始字元的索引值。 翻譯:在 Java 中建立字串物件 - 用法下面的程式碼經過簡化,僅包含演示問題的基礎知識。
//JDK 6
String(int offset, int count, char value[]) {
	this.value = value;
	this.offset = offset;
	this.count = count;
}

public String substring(int beginIndex, int endIndex) {
	//check boundary
	return  new String(offset + beginIndex, endIndex - beginIndex, value);
}

4. JDK 6中substring()所引起的問題

如果你有一個非常長的字串,但你只需要它的一小部分,每次使用substring(). 這將導致執行問題,因為您只需要一小部分,但仍然必須儲存整個字串。對於 JDK 6,解決方案是下面的程式碼,它將字串轉換為真正的子字串:
x = x.substring(x, y) + ""
用戶STepeR提出了一個問題(請參閱他的評論),似乎有必要添加第4點。「substring()JDK 6 中引起的問題」是一個更廣泛的範例。我希望這將是答案,並將幫助其他人快速找出問題所在。這是代碼:
String a = "aLongLongString";
String b = a.substring(1, 2);
String c = a.substring(2, 6);
因此,在 JDK 7 中b,透過呼叫 aс類型物件的方法所建立的a 類型物件將引用堆中兩個新建立的陣列 - for 、for 。這兩個新數組將與a 引用的原始數組一起儲存在堆上。那些。原始數組不會在任何地方消失。現在讓我們回到 JDK 6。在 JDK 6 中,堆包含單一陣列。執行程式碼行後 Stringsubstring()StringLbongLcaLongLongStringaLongLongString
String b = a.substring(1, 2);
String c = a.substring(2, 6);
物件b引用c堆中的同一個數組,對應於物件ab- 從第一個索引到第二個索引的元素,c- 從第二個索引到第六個索引的元素(編號從0開始,提醒)。那些。顯然,b在 JDK 6 中對變數或 c 的任何進一步存取實際上都會導致原始數組的所需元素被「計數」到堆中。在 JDK 7 中,對變數b或 c 的任何進一步存取都會導致對已在堆中建立並「存活」的必要的較小數組的存取。那些。顯然,在這種情況下,JDK 7 在物理上使用了更多記憶體。但讓我們想像一個可能的選擇:變數的某些子字串被分配給變量b,並且將來每個人都只使用它們 - 物件和。沒有人再簡單地存取變數 a;沒有對它的引用(這就是本文作者的意思)。結果,在某個時間點垃圾收集器被觸發,並且(當然,以最一般的形式)我們得到兩種不同的情況: JDK 6:對像被銷毀(垃圾收集),但是 - 原始的巨大數組堆裡是活的;它被不斷地使用並且。 JDK 7:物件 a 與堆疊中的原始陣列一起被銷毀。這就是 JDK 6 中可能導致記憶體洩漏的地方。 cabcabc

5. JDK 7 中的 substring()

該方法在JDK 7中得到了改進。在 JDK 7 中,substring()它實際上在堆上建立了一個新陣列。 翻譯:在 Java 中建立字串物件 - 用法
//JDK 7
public String(char value[], int offset, int count) {
	//check boundary
	this.value = Arrays.copyOfRange(value, offset, offset + count);
}

public String substring(int beginIndex, int endIndex) {
	//check boundary
	int subLen = endIndex - beginIndex;
	return new String(value, beginIndex, subLen);
}
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION