JavaRush /จาวาบล็อก /Random-TH /การแปล: การสร้างวัตถุ String ใน Java - โดยใช้ " " หรือตัว...
FellowSparrow
ระดับ
Lvov

การแปล: การสร้างวัตถุ String ใน Java - โดยใช้ " " หรือตัวสร้าง?

เผยแพร่ในกลุ่ม
ต้นฉบับ: สร้างสตริง 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==bจริง เนื่องจากaทั้งคู่bอ้างถึงออบเจ็กต์เดียวกัน - สตริงที่ประกาศเป็นตัวอักษร (สตริงตามตัวอักษรด้านล่าง) ในพื้นที่วิธีการ (เราอ้างอิงผู้อ่านถึงแหล่งที่มาในทรัพยากรของเรา: ไดอะแกรม8 อันดับแรกสำหรับการทำความเข้าใจ Javaไดอะแกรม 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==dเท็จเนื่องจาก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 เสมอ การใช้ Constructor จะสร้างอ็อบเจ็กต์ที่ไม่จำเป็นเพิ่มเติม ดังนั้นควรใช้เครื่องหมายคำพูดคู่หากคุณต้องการสร้างสตริง หากคุณต้องการสร้างวัตถุใหม่บนฮีปจริงๆ คุณควรใช้ตัวสร้าง กรณีการใช้งานแสดงไว้ที่นี่ (ต้นฉบับ) (ฉันให้ข้อความที่แปลไว้ด้านล่าง แต่ฉันยังคงขอแนะนำอย่างยิ่งให้คุณทำความคุ้นเคยกับโค้ดของผู้แสดงความเห็นที่ลิงก์นี้)

วิธีการ substring() ใน JDK 6 และ JDK 7

วิธีการสตริงย่อย () ใน JDK 6 และ JDK 7โดย X Wang วิธีการsubstring(int beginIndex, int endIndex)ใน JDK 6 และ JDK 7 นั้นแตกต่างกัน การทราบความแตกต่างเหล่านี้จะช่วยให้คุณใช้วิธีนี้ได้ดีขึ้น เพื่อความสะดวกในการอ่าน ด้านล่างนี้substring()เราจะหมายถึงไวยากรณ์แบบเต็ม เช่น substring(int beginIndex, int endIndex).

1. substring() ทำหน้าที่อะไร?

วิธีการsubstring(int beginIndex, int endIndex)ส่งคืนสตริงที่ขึ้นต้นด้วยหมายเลขอักขระ และลงท้ายด้วย หมายเลข beginIndexอักขระ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

ประเภทสตริงได้รับการสนับสนุนตามประเภทcharอาร์เรย์ ใน JDK 6 คลาสStringประกอบด้วย 3 ฟิลด์: char value[], int offset, int 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. ปัญหาที่เกิดจาก substring() ใน JDK 6

หากคุณมีสายอักขระที่ยาวมาก แต่คุณต้องการเพียงส่วนเล็กๆ เท่านั้น ซึ่งคุณจะได้ทุกครั้งที่ใช้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 ที่สร้างขึ้นโดยการ เรียกStringใช้เมธอดsubstring()บนออบเจ็กต์ประเภท a Stringจะอ้างอิงอาร์เรย์ที่สร้างขึ้นใหม่สองตัวในฮีป - Lสำหรับb, ongLสำหรับ cอาร์เรย์ใหม่ทั้งสองนี้จะถูกเก็บไว้ในฮีปพร้อมกับอาร์เรย์ดั้งเดิมaLongLongStringที่อ้างอิงโดย a เหล่านั้น. อาเรย์ดั้งเดิมไม่ได้หายไปไหน ตอนนี้กลับมาที่ JDK 6 กัน ใน JDK 6 ฮีปจะมีอาร์เรย์aLongLongStringเดียว หลังจากรันโค้ดบรรทัดแล้ว
String b = a.substring(1, 2);
String c = a.substring(2, 6);
วัตถุbอ้างcถึงอาร์เรย์เดียวกันในฮีปซึ่งสอดคล้องกับวัตถุa: b- ถึงองค์ประกอบจากดัชนีที่ 1 ถึงดัชนีที่ 2 c- ถึงองค์ประกอบจากดัชนีที่ 2 ถึงอันดับที่ 6 (การกำหนดหมายเลขเริ่มจาก 0 การแจ้งเตือน) เหล่านั้น. แน่นอนว่าการเข้าถึงตัวแปรหรือ c ใน JDK 6 เพิ่มเติมbจะส่งผลให้องค์ประกอบที่ต้องการของอาร์เรย์ดั้งเดิมถูก "นับ" ลงในฮีป ใน JDK 7 การเข้าถึงตัวแปรหรือ c เพิ่มเติมbจะทำให้เกิดการเข้าถึงอาร์เรย์ขนาดเล็กที่จำเป็นซึ่งได้ถูกสร้างขึ้นแล้วและ "ใช้งานจริง" ในฮีป เหล่านั้น. เห็นได้ชัดว่า JDK 7 ใช้หน่วยความจำมากขึ้นในสถานการณ์เช่นนี้ แต่ลองจินตนาการถึงตัวเลือกที่เป็นไปได้: สตริงย่อยบางตัวของตัวแปรถูกกำหนดให้กับตัวแปรbและในอนาคตทุกคนจะใช้เฉพาะพวกมันเท่านั้น - อ็อบเจ็กต์และ. ไม่มีใครเข้าถึงตัวแปร a อีกต่อไป ไม่มีการอ้างอิงถึงมัน (นี่คือความหมายของผู้เขียนบทความ) เป็นผลให้ ณ จุดหนึ่งตัวรวบรวมขยะถูกกระตุ้นและ (ในรูปแบบทั่วไปที่สุดแน่นอน) เราจะได้รับ 2 สถานการณ์ที่แตกต่างกัน: JDK 6 : วัตถุถูกทำลาย (เก็บขยะ) แต่ - อาเรย์ขนาดใหญ่ดั้งเดิม ในกองนั้นยังมีชีวิตอยู่ มีการใช้อย่างต่อเนื่อง และ JDK 7:วัตถุ a ถูกทำลายพร้อมกับอาร์เรย์ดั้งเดิมในฮีป นี่คือประเด็นใน JDK 6 ที่อาจทำให้หน่วยความจำรั่ว cabcabc

5. สตริงย่อย () ใน JDK 7

วิธีการได้รับการปรับปรุงใน 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