สตริงคงที่พูลในชวา
การสร้างวัตถุสตริงมีสองรูปแบบใน Java หนึ่งคือรูปแบบที่แท้จริงเช่น string str = "droid"; และอื่น ๆ เป็นวิธีมาตรฐานในการสร้างวัตถุโดยใช้ใหม่เช่นสตริง str = สตริงใหม่ ("droid"); เรามักจะใช้วิธีการทั้งสองนี้เมื่อเขียนโค้ดโดยเฉพาะอย่างยิ่งวิธีการตามตัวอักษร อย่างไรก็ตามการใช้งานทั้งสองนี้มีความแตกต่างในการใช้งานและการใช้หน่วยความจำ ทั้งหมดนี้เป็นเพราะความจริงที่ว่า JVM รักษาหน่วยความจำพิเศษเพื่อลดการสร้างวัตถุสตริงซ้ำซึ่งเป็นพูลคงที่สตริงหรือพูลตามตัวอักษรสตริง
มันทำงานอย่างไร
เมื่อวัตถุสตริงถูกสร้างขึ้นในรูปแบบตัวอักษรในรหัส JVM จะตรวจสอบตัวอักษรก่อน หากมีการอ้างอิงไปยังวัตถุสตริงที่มีเนื้อหาเดียวกันในพูลคงที่สตริงการอ้างอิงจะถูกส่งคืน มิฉะนั้นวัตถุสตริงใหม่จะถูกสร้างขึ้นจากนั้นการอ้างอิงจะถูกวางลงในพูลคงที่สตริงคงที่และการอ้างอิงจะถูกส่งคืน
ยกตัวอย่าง
รูปแบบการสร้างตัวอักษร
string str1 = "droid";
JVM ตรวจพบตัวอักษรนี้ที่นี่เราคิดว่าไม่มีวัตถุที่มีเนื้อหามีอยู่ JVM ไม่สามารถค้นหาวัตถุสตริงที่มีเนื้อหา droid ผ่านพูลคงที่สตริงดังนั้นมันจะสร้างวัตถุสตริงนี้จากนั้นใส่การอ้างอิงของวัตถุที่คุณเพิ่งสร้างลงในพูลคงที่สตริงและส่งคืนการอ้างอิงไปยังตัวแปร STR1
หากมีรหัสเช่นนี้ต่อไป
string str2 = "droid";
ในทำนองเดียวกัน JVM ยังคงต้องตรวจจับตัวอักษรนี้ โดยการค้นหาพูลคงที่สตริงคงที่ JVM พบว่าเนื้อหาเป็นวัตถุสตริง "droid" อยู่ดังนั้นจึงส่งคืนการอ้างอิงของวัตถุสตริงที่มีอยู่ไปยังตัวแปร STR2 โปรดทราบว่าวัตถุสตริงใหม่จะไม่ถูกสร้างขึ้นใหม่ที่นี่
ตรวจสอบว่า str1 และ str2 ชี้ไปที่วัตถุเดียวกันเราสามารถใช้รหัสนี้ได้
System.out.println (str1 == str2);
ผลลัพธ์เป็นจริง
สร้างด้วยใหม่
string str3 = สตริงใหม่ ("droid");
เมื่อเราใช้ใหม่เพื่อสร้างวัตถุสตริงวัตถุสตริงใหม่จะถูกสร้างขึ้นโดยไม่คำนึงว่ามีการอ้างอิงถึงวัตถุที่มีเนื้อหาเดียวกันในพูลคงที่สตริง ลองใช้รหัสต่อไปนี้เพื่อทดสอบ
string str3 = สตริงใหม่ ("droid");
System.out.println (str1 == str3);
ผลลัพธ์เป็นเท็จตามที่เราคิดว่าแสดงว่าตัวแปรทั้งสองชี้ไปที่วัตถุที่แตกต่างกัน
ฝึกงาน
สำหรับวัตถุสตริงที่สร้างขึ้นด้วยใหม่ด้านบนหากคุณต้องการเพิ่มการอ้างอิงไปยังพูลคงที่สตริงคงที่คุณสามารถใช้วิธีการฝึกงาน
หลังจากโทรเข้าฝึกงานก่อนอื่นให้ตรวจสอบว่ามีการอ้างอิงถึงวัตถุในพูลคงที่สตริงหรือไม่ หากมีอยู่ให้ส่งคืนการอ้างอิงนี้ไปยังตัวแปรมิฉะนั้นการอ้างอิงจะถูกเพิ่มและส่งคืนไปยังตัวแปร
string str4 = str3.intern ();
System.out.println (str4 == str1);
ผลลัพธ์ผลลัพธ์เป็นจริง
ปัญหายาก
ข้อกำหนดเบื้องต้น?
สิ่งที่จำเป็นสำหรับการใช้พูลคงที่สตริงคงที่คือวัตถุสตริงใน Java นั้นไม่เปลี่ยนรูปซึ่งสามารถตรวจสอบให้แน่ใจว่าตัวแปรหลายตัวแบ่งปันวัตถุเดียวกันอย่างปลอดภัย หากวัตถุสตริงใน Java เป็นตัวแปรและการดำเนินการอ้างอิงหนึ่งครั้งจะเปลี่ยนค่าของวัตถุตัวแปรอื่น ๆ จะได้รับผลกระทบเช่นกันเห็นได้ชัดว่านี่ไม่มีเหตุผล
การอ้างอิงหรือวัตถุ
คำถามนี้เป็นเรื่องธรรมดามากที่สุดเมื่อเก็บพูลค่าคงที่สตริงไว้ในการอ้างอิงหรือวัตถุ พูลคงที่สตริงเก็บการอ้างอิงวัตถุไม่ใช่วัตถุ ใน Java วัตถุถูกสร้างขึ้นในหน่วยความจำฮีป
การตรวจสอบอัปเดตความคิดเห็นที่ได้รับจำนวนมากยังพูดถึงปัญหานี้และฉันก็ตรวจสอบ ตรวจสอบสภาพแวดล้อม
22: 18: 54-androidyue ~/videos $ cat/etc/os-releasename = fedoraversion = "17 (Miracle Beefy)" id = fedoraversion_id = 17pretty_name = "Fedora 17 (Beefy Miracle) "ansi_color =" 0; 34 "cpe_name =" cpe:/o: fedoraproject: fedora: 17 "22: 19: 04-androidyue ~/videos $ java -versionjava เวอร์ชัน" 1.7.0_25 "OpenJDK เซิร์ฟเวอร์ 64 บิต VM (สร้าง 23.7-B01, โหมดผสม)
แนวคิดการตรวจสอบ: โปรแกรม Java ต่อไปนี้อ่านไฟล์วิดีโอขนาด 82m และดำเนินการฝึกงานในรูปแบบของสตริง
22: 01: 17 -Androidyue ~/วิดีโอ $ ll -lh | grep Why_to_learn.mp4-rw-rw-r-- 1 Androidue Androidyue 82m ตุลาคม 20 2013 Why_to_learn.mp4
รหัสการตรวจสอบ
นำเข้า java.io.bufferedreader; นำเข้า java.io.filenotfoundexception; นำเข้า java.io.filereader; นำเข้า Java.io.ioException; Public Class Testmain {สตริงคงที่ส่วนตัว โมฆะคงที่สาธารณะหลัก (สตริง [] args) {fileContent = readFileToString (args [0]); if (null! = fileContent) {fileContent = fileContent.intern (); System.out.println ("ไม่ใช่ Null"); }} สตริงคงที่ส่วนตัว readFileToString (ไฟล์สตริง) {bufferedReader reader = null; ลอง {reader = ใหม่ bufferedReader (ใหม่ filereader (ไฟล์)); StringBuffer buff = new StringBuffer (); สายสตริง; ในขณะที่ ((line = reader.readline ())! = null) {buff.append (บรรทัด); } return buff.toString (); } catch (filenotfoundException e) {e.printStackTrace (); } catch (ioexception e) {e.printstacktrace (); } ในที่สุด {ถ้า (null! = reader) {ลอง {reader.close (); } catch (ioexception e) {e.printstacktrace (); }}} return null; -เนื่องจากพูลคงที่สตริงคงที่อยู่ในรุ่นถาวรในหน่วยความจำฮีปจึงเหมาะสมก่อน Java 8 เราตรวจสอบโดยการตั้งค่าถาวรของค่าเล็ก ๆ หากวัตถุสตริงมีอยู่ในพูลคงที่สตริง java.lang.outofMemoryError ข้อผิดพลาดพื้นที่ permgen จะต้องถูกโยนทิ้ง
java -xx: permsize = 6m testmain ~/videos/Why_to_learn.mp4
การเรียกใช้โปรแกรมพิสูจน์ไม่ได้โยน oom แต่สิ่งนี้ไม่สามารถพิสูจน์ได้ว่ามันถูกเก็บไว้เป็นวัตถุหรือการอ้างอิง
แต่อย่างน้อยนี่ก็พิสูจน์ได้ว่าเนื้อหาเนื้อหาจริง char [] ของสตริงไม่ได้ถูกเก็บไว้ในพูลคงที่สตริง ในกรณีนี้มันไม่สำคัญมากที่สตริงคงที่พูลจะเก็บข้อมูลอ้างอิงไปยังวัตถุสตริงหรือวัตถุสตริง แต่บุคคลยังคงมีแนวโน้มที่จะจัดเก็บข้อมูลอ้างอิง
ข้อดีและข้อเสีย
ข้อได้เปรียบของการรวมค่าสตริงคงที่คือการลดการสร้างสตริงของเนื้อหาเดียวกันและบันทึกพื้นที่หน่วยความจำ
หากคุณต้องพูดข้อเสียมันก็คือการเสียสละเวลาในการคำนวณ CPU เพื่อแลกเปลี่ยนพื้นที่ เวลาการคำนวณ CPU ส่วนใหญ่จะใช้เพื่อค้นหาว่ามีการอ้างอิงถึงวัตถุที่มีเนื้อหาเดียวกันในพูลคงที่สตริงหรือไม่ อย่างไรก็ตามการใช้งานภายในนั้นเป็นแฮชต์ได้ดังนั้นต้นทุนการคำนวณจึงต่ำ
การรีไซเคิล GC?
เนื่องจากพูลคงที่สตริงคงที่มีการอ้างอิงถึงวัตถุสตริงที่ใช้ร่วมกันนี่หมายความว่าวัตถุเหล่านี้ไม่สามารถรีไซเคิลได้หรือไม่?
ก่อนอื่นวัตถุที่ใช้ร่วมกันในคำถามมักจะเล็กลง เท่าที่ฉันได้ตรวจสอบแล้วมีปัญหาเช่นนี้ในเวอร์ชันก่อนหน้า แต่ด้วยการแนะนำการอ้างอิงที่อ่อนแอปัญหานี้ควรหายไปในปัจจุบัน
เกี่ยวกับปัญหานี้คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับบทความนี้ Strings Interned: อภิธานศัพท์ Java
ใช้ฝึกงาน?
ข้อกำหนดเบื้องต้นสำหรับการใช้ฝึกงานคือคุณรู้ว่าคุณต้องใช้มันจริงๆ ตัวอย่างเช่นเรามีบันทึกหลายล้านที่นี่ซึ่งค่าที่แน่นอนของบันทึกคือแคลิฟอร์เนียสหรัฐอเมริกาหลายครั้ง เราไม่ต้องการสร้างวัตถุสตริงนับล้าน เราสามารถใช้ฝึกงานเพื่อเก็บสำเนาเดียวในหน่วยความจำ สำหรับความเข้าใจในเชิงลึกของผู้ฝึกงานโปรดดูการวิเคราะห์เชิงลึกของ String#Intern
มีข้อยกเว้นอยู่เสมอหรือไม่?
คุณรู้หรือไม่ว่ารหัสต่อไปนี้จะสร้างวัตถุสตริงหลายอย่างและบันทึกการอ้างอิงหลายอย่างในพูลคงที่สตริงหรือไม่
String Test = "A" + "B" + "C";
คำตอบคือมีเพียงวัตถุเดียวเท่านั้นที่ถูกสร้างขึ้นและมีการอ้างอิงเพียงรายการเดียวในพูลคงที่ เราใช้การสลายตัวของ Javap และดูมัน
17:02 $ JAVAP -C TestInternedPoolgCcompiled จาก "testinternedpoolgc.java" ระดับสาธารณะ testinternednedpoolgc ขยาย java.lang.Object {public testinternedPoolgc (); รหัส: 0: Aload_0 1: Invokespecial #1; // วิธีการ java/lang/object. "<int>" :() v 4: returnpublic static void main (java.lang.string []) โยน java.lang.exception; รหัส: 0: LDC #2; // String ABC 2: Store_1 3: returnคุณเคยเห็นไหม ในความเป็นจริงในช่วงระยะเวลาการรวบรวมตัวอักษรทั้งสามนี้ได้ถูกสังเคราะห์เป็นหนึ่งเดียว นี่คือการเพิ่มประสิทธิภาพที่หลีกเลี่ยงการสร้างวัตถุสตริงซ้ำซ้อนและไม่มีปัญหาการเย็บสตริง สำหรับการเย็บสตริงคุณสามารถดูรายละเอียด Java: การเย็บสตริง
ข้างต้นเป็นการรวบรวมข้อมูลเกี่ยวกับพูลคงที่สตริงใน Java เราจะยังคงเพิ่มข้อมูลที่เกี่ยวข้องในอนาคต ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!