ทำไมพวกเขาถึงตัดสินใจทำให้String
ไม่เปลี่ยนรูปแบบใน Java และ. NET (และภาษาอื่น ๆ )? ทำไมพวกเขาถึงไม่ทำให้มันเปลี่ยนแปลงได้?
String
เป็นจริงที่ไม่แน่นอนภายใน StringBuilder
ใน NET 2.0 แปรรูปสตริง ฉันจะทิ้งไว้ที่นี่
ทำไมพวกเขาถึงตัดสินใจทำให้String
ไม่เปลี่ยนรูปแบบใน Java และ. NET (และภาษาอื่น ๆ )? ทำไมพวกเขาถึงไม่ทำให้มันเปลี่ยนแปลงได้?
String
เป็นจริงที่ไม่แน่นอนภายใน StringBuilder
ใน NET 2.0 แปรรูปสตริง ฉันจะทิ้งไว้ที่นี่
คำตอบ:
อ้างอิงจากJava ที่มีประสิทธิภาพ , บทที่ 4, หน้า 73, ฉบับที่ 2:
"มีหลายเหตุผลที่ดีสำหรับสิ่งนี้: คลาสที่ไม่เปลี่ยนรูปนั้นง่ายต่อการออกแบบใช้งานและใช้งานมากกว่าคลาสที่ไม่สามารถเปลี่ยนแปลงได้
[ ... ]
" วัตถุที่ไม่เปลี่ยนรูปนั้นเป็นสิ่งที่เรียบง่ายวัตถุที่ไม่เปลี่ยนรูปนั้นสามารถอยู่ในสถานะเดียวกับสถานะที่มันถูกสร้างขึ้นได้หากคุณแน่ใจว่าผู้สร้างทุกคนสร้างค่าคงที่ของชั้นเรียน ไม่มีความพยายามในส่วนของคุณ
[ ... ]
วัตถุที่ไม่เปลี่ยนรูปนั้นมีความปลอดภัยต่อเธรด พวกเขาไม่ต้องการการประสาน พวกเขาไม่สามารถเสียหายได้โดยหลายกระทู้เข้าถึงพวกเขาพร้อมกัน นี่เป็นวิธีที่ง่ายที่สุดในการบรรลุความปลอดภัยของเธรด ในความเป็นจริงไม่มีเธรดที่สามารถสังเกตเห็นผลกระทบของเธรดอื่นบนวัตถุที่ไม่เปลี่ยนรูป ดังนั้น วัตถุที่ไม่เปลี่ยนรูปสามารถแบ่งปันได้อย่างอิสระ
[ ... ]
จุดเล็ก ๆ อื่น ๆ จากบทเดียวกัน:
ไม่เพียง แต่คุณสามารถแบ่งปันวัตถุที่ไม่เปลี่ยนรูปแบบ แต่คุณสามารถแบ่งปันภายในของพวกเขา
[ ... ]
วัตถุที่ไม่เปลี่ยนรูปสร้างสิ่งปลูกสร้างที่ยอดเยี่ยมสำหรับวัตถุอื่น ๆ ไม่ว่าจะไม่แน่นอนหรือไม่เปลี่ยนรูป
[ ... ]
ข้อเสียที่แท้จริงเพียงอย่างเดียวของคลาสที่ไม่เปลี่ยนรูปคือพวกเขาต้องการวัตถุแยกต่างหากสำหรับแต่ละค่าที่แตกต่าง
report2.Text = report1.Text;
ยกตัวอย่างเช่นการคัดลอกรายงาน: report2.Text.Replace(someWord, someOtherWord);
แล้วที่อื่นการปรับเปลี่ยนข้อความ: สิ่งนี้จะเปลี่ยนรายงานฉบับแรกและฉบับที่สอง
มีเหตุผลอย่างน้อยสองประการ
First - ความปลอดภัย http://www.javafaq.nu/java-article1060.html
สาเหตุหลักที่ทำให้ String ไม่สามารถเปลี่ยนแปลงได้คือความปลอดภัย ดูตัวอย่างนี้: เรามีวิธีเปิดไฟล์พร้อมการตรวจสอบการเข้าสู่ระบบ เราส่งสตริงไปยังวิธีนี้เพื่อประมวลผลการรับรองความถูกต้องซึ่งจำเป็นก่อนที่การโทรจะถูกส่งผ่านไปยังระบบปฏิบัติการ หาก String ไม่สามารถเปลี่ยนแปลงได้อาจเป็นไปได้ที่จะแก้ไขเนื้อหาหลังจากการตรวจสอบความถูกต้องก่อนที่ OS จะได้รับการร้องขอจากโปรแกรมดังนั้นจึงเป็นไปได้ที่จะร้องขอไฟล์ใด ๆ ดังนั้นหากคุณมีสิทธิ์ที่จะเปิดไฟล์ข้อความในไดเรกทอรีผู้ใช้ แต่เมื่อใดก็ตามที่คุณจัดการเพื่อเปลี่ยนชื่อไฟล์คุณสามารถร้องขอให้เปิดไฟล์ "passwd" หรืออื่น ๆ จากนั้นไฟล์สามารถแก้ไขได้และจะสามารถเข้าสู่ระบบปฏิบัติการโดยตรงได้
ที่สอง - ประสิทธิภาพของหน่วยความจำ http://hikrish.blogspot.com/2006/07/why-string-class-is-immutable.html
JVM ดูแลรักษา "String Pool" ภายใน เพื่อเพิ่มประสิทธิภาพหน่วยความจำ JVM จะอ้างถึงวัตถุ String จากกลุ่ม มันจะไม่สร้างวัตถุ String ใหม่ ดังนั้นเมื่อใดก็ตามที่คุณสร้างสตริงตัวอักษรใหม่ JVM จะตรวจสอบในกลุ่มว่ามีอยู่แล้วหรือไม่ หากมีอยู่ในกลุ่มแล้วให้อ้างอิงไปยังวัตถุเดียวกันหรือสร้างวัตถุใหม่ในกลุ่ม จะมีการอ้างอิงจำนวนมากชี้ไปที่วัตถุ String เดียวกันหากมีคนเปลี่ยนค่ามันจะมีผลต่อการอ้างอิงทั้งหมด ดังนั้นดวงอาทิตย์จึงตัดสินใจทำให้มันไม่เปลี่ยนรูป
ที่จริงแล้วสตริงเหตุผลไม่เปลี่ยนรูปแบบใน java ไม่ได้มีส่วนเกี่ยวข้องกับความปลอดภัยมากนัก เหตุผลหลักสองข้อต่อไปนี้:
สตริงเป็นวัตถุชนิดที่ใช้กันอย่างแพร่หลาย ดังนั้นจึงรับประกันได้มากหรือน้อยที่จะใช้ในสภาพแวดล้อมแบบมัลติเธรด สตริงไม่สามารถเปลี่ยนแปลงได้เพื่อให้แน่ใจว่าปลอดภัยที่จะแชร์สตริงระหว่างเธรด การมีสตริงที่ไม่เปลี่ยนรูปทำให้มั่นใจได้ว่าเมื่อผ่านสตริงจากเธรด A ไปยังเธรด B อื่นเธรด B ไม่สามารถแก้ไขสตริงของเธรด A โดยไม่คาดคิดได้
สิ่งนี้ไม่เพียงช่วยลดความซับซ้อนของงานการเขียนโปรแกรมแบบมัลติเธรดที่ซับซ้อนอยู่แล้ว แต่ยังช่วยให้มีประสิทธิภาพการทำงานของแอพพลิเคชั่นแบบมัลติเธรดอีกด้วย การเข้าถึงวัตถุที่ไม่แน่นอนต้องทำข้อมูลให้ตรงกันอย่างใดอย่างหนึ่งเมื่อพวกเขาสามารถเข้าถึงได้จากหลายกระทู้เพื่อให้แน่ใจว่าหนึ่งด้ายไม่ได้พยายามที่จะอ่านค่าของวัตถุของคุณในขณะที่มันถูกแก้ไขโดยหัวข้ออื่น การซิงโครไนซ์ที่เหมาะสมนั้นเป็นเรื่องยากที่จะทำอย่างถูกต้องสำหรับโปรแกรมเมอร์ ไม่สามารถแก้ไขวัตถุที่ไม่เปลี่ยนรูปได้ดังนั้นจึงไม่จำเป็นต้องทำการซิงโครไนซ์
ในขณะที่ String Interning ได้รับการกล่าวถึงมันแสดงถึงเพียงเล็กน้อยในประสิทธิภาพของหน่วยความจำสำหรับโปรแกรม Java เฉพาะตัวอักษรสตริงเท่านั้นที่จะถูกฝึกงาน ซึ่งหมายความว่าเฉพาะสตริงที่เหมือนกันในซอร์สโค้ดของคุณเท่านั้นที่จะแชร์ Object String เดียวกัน ถ้าโปรแกรมของคุณสร้างสตริงที่เหมือนกันมันจะแสดงเป็นวัตถุต่าง ๆ
ที่สำคัญกว่านั้นคือสตริงที่ไม่เปลี่ยนแปลงทำให้พวกเขาสามารถแชร์ข้อมูลภายในของพวกเขาได้ สำหรับการดำเนินการกับสตริงจำนวนมากหมายความว่าไม่จำเป็นต้องคัดลอกอาร์เรย์ของอักขระพื้นฐาน ตัวอย่างเช่นสมมติว่าคุณต้องการใช้อักขระห้าตัวแรกของ String ใน Java คุณจะเรียก myString.substring (0,5) ในกรณีนี้สิ่งที่วิธีย่อย () วิธีการเพียงแค่การสร้างวัตถุสตริงใหม่ที่ใช้ร่วมกันพื้นฐานของ char [] แต่ใครจะรู้ว่ามันเริ่มต้นที่ดัชนี 0 และสิ้นสุดที่ดัชนี 5 ของถ่าน [] หากต้องการวางสิ่งนี้ในรูปแบบกราฟิกคุณจะต้องทำสิ่งต่อไปนี้:
| myString |
v v
"The quick brown fox jumps over the lazy dog" <-- shared char[]
^ ^
| | myString.substring(0,5)
สิ่งนี้ทำให้การดำเนินการชนิดนี้ราคาถูกมากและ O (1) เนื่องจากการดำเนินการไม่ขึ้นอยู่กับความยาวของสายอักขระดั้งเดิมหรือความยาวของสตริงย่อยที่เราต้องการแยก ลักษณะการทำงานนี้ยังมีประโยชน์หน่วยความจำบางอย่างเนื่องจากสตริงจำนวนมากสามารถแบ่งปันอักขระพื้นฐาน []
char[]
นั้นเป็นการตัดสินใจออกแบบที่ค่อนข้างน่าสงสัย หากคุณอ่านไฟล์ทั้งหมดลงในสายอักขระเดียวและเก็บการอ้างอิงถึงสตริงย่อย 1 ตัวอักษรไฟล์ทั้งหมดจะต้องถูกเก็บไว้ในหน่วยความจำ
String.substring()
ดำเนินการสำเนาแบบเต็มเพื่อป้องกันปัญหาที่กล่าวถึงในความคิดเห็นด้านบน ใน Java 8 ทั้งสองฟิลด์ที่เปิดใช้งานchar[]
การแชร์คือcount
และoffset
จะถูกลบออกซึ่งเป็นการลดการปล่อยหน่วยความจำของอินสแตนซ์ของสตริง
ความปลอดภัยและประสิทธิภาพของเธรด หากไม่สามารถแก้ไขสตริงได้จะปลอดภัยและรวดเร็วในการส่งต่อการอ้างอิงไปยังหลาย ๆ เธรด หากสตริงไม่แน่นอนคุณจะต้องคัดลอกไบต์ทั้งหมดของสตริงไปยังอินสแตนซ์ใหม่หรือจัดทำข้อมูลให้ตรงกัน แอปพลิเคชันทั่วไปจะอ่านสตริง 100 ครั้งทุกครั้งที่จำเป็นต้องแก้ไขสตริง ดูวิกิพีเดียเกี่ยวกับการเปลี่ยนไม่ได้
เราควรถามว่า "ทำไม X จึงไม่แน่นอน" เป็นการเริ่มต้นที่ดีกว่าความไม่สามารถเปลี่ยนแปลงได้เนื่องจากประโยชน์ที่ได้รับจากเจ้าหญิงฟลัฟ ควรเป็นข้อยกเว้นว่ามีบางอย่างไม่แน่นอน
น่าเสียดายที่ภาษาโปรแกรมส่วนใหญ่ในปัจจุบันใช้ค่าเริ่มต้นเป็นความไม่แน่นอน แต่หวังว่าในอนาคตค่าเริ่มต้นจะเปลี่ยนไปเป็น immutablity มากขึ้น (ดูรายการที่ต้องการสำหรับภาษาโปรแกรมหลักต่อไป )
ว้าว! ฉันไม่อยากเชื่อข้อมูลที่ผิดที่นี่ String
การเป็นคนไม่เปลี่ยนรูปไม่มีอะไรกับความปลอดภัย หากมีใครบางคนสามารถเข้าถึงวัตถุในแอปพลิเคชั่นที่กำลังทำงานอยู่ (ซึ่งจะต้องมีการสันนิษฐานไว้ก่อนว่าคุณกำลังพยายามป้องกันคนที่ 'แฮ็ค'String
ในแอพของคุณ) พวกเขาจะเป็นโอกาสอื่น ๆ อีกมากมายสำหรับการแฮ็ค
มันเป็นความคิดที่แปลกใหม่ที่เปลี่ยนไม่ได้ของ String
การจัดการกับปัญหาเกลียว อืม ... ฉันมีวัตถุที่ถูกเปลี่ยนแปลงโดยเธรดที่แตกต่างกันสองรายการ ฉันจะแก้ไขปัญหานี้ได้อย่างไร ซิงโครไนซ์การเข้าถึงวัตถุหรือไม่ Naawww ... อย่าปล่อยให้ใครมาเปลี่ยนวัตถุเลย - นั่นจะช่วยแก้ไขปัญหาที่เกิดขึ้นพร้อมกันทั้งหมดของเรา! ในความเป็นจริงเรามาทำให้วัตถุทั้งหมดไม่เปลี่ยนรูปและจากนั้นเราสามารถลบโครงสร้างที่ซิงโคไนซ์ออกจากภาษาจาวา
เหตุผลที่แท้จริง (ชี้ให้เห็นโดยคนอื่นข้างต้น) คือการเพิ่มประสิทธิภาพหน่วยความจำ มันค่อนข้างทั่วไปในแอปพลิเคชันใด ๆ สำหรับตัวอักษรสตริงเดียวกันที่จะใช้ซ้ำ ๆ ในความเป็นจริงมันเป็นเรื่องธรรมดามากที่ทศวรรษที่ผ่านมาคอมไพเลอร์จำนวนมากได้ทำการเพิ่มประสิทธิภาพของการจัดเก็บเพียงตัวอย่างเดียวของString
ตัวอักษร ข้อเสียเปรียบของการปรับให้เหมาะสมนี้คือรหัสรันไทม์ที่แก้ไขString
ตัวอักษรแนะนำปัญหาเนื่องจากมีการปรับเปลี่ยนอินสแตนซ์สำหรับรหัสอื่น ๆ ทั้งหมดที่ใช้ร่วมกัน ยกตัวอย่างเช่นมันจะไม่ดีสำหรับบางฟังก์ชั่นในการประยุกต์ใช้ในการเปลี่ยนแปลงString
ที่แท้จริงที่จะ"dog"
จะส่งผลให้ถูกเขียนไป stdout ด้วยเหตุนี้จึงจำเป็นต้องมีวิธีการป้องกันโค้ดที่พยายามเปลี่ยน"cat"
printf("dog")
"cat"
String
ตัวอักษร (เช่นทำให้ไม่เปลี่ยนรูป) คอมไพเลอร์บางตัว (ที่ได้รับการสนับสนุนจากระบบปฏิบัติการ) จะทำสิ่งนี้ได้โดยการวางตัวString
แท้จริงในเซ็กเมนต์หน่วยความจำแบบอ่านอย่างเดียวที่จะทำให้เกิดความผิดพลาดของหน่วยความจำถ้ามีความพยายามในการเขียน
ในชวาสิ่งนี้เรียกว่าการฝึกงาน คอมไพเลอร์ Java ที่นี่เป็นเพียงการติดตามการเพิ่มประสิทธิภาพหน่วยความจำมาตรฐานที่ทำโดยคอมไพเลอร์มานานหลายทศวรรษ และเพื่อแก้ไขปัญหาเดียวกันของString
ตัวอักษรเหล่านี้ที่ถูกแก้ไขที่รันไทม์ Java เพียงทำให้String
คลาสไม่เปลี่ยนรูป (i. e ไม่มีตัวตั้งค่าที่อนุญาตให้คุณเปลี่ยนString
เนื้อหา) String
s จะไม่ต้องไม่เปลี่ยนรูปถ้าString
ไม่ได้เกิดจากการฝึกตัวอักษร
String
และStringBuffer
แต่น่าเสียดายที่มีเพียงไม่กี่ประเภทที่ตามมา
String
ไม่ใช่ประเภทดึกดำบรรพ์ แต่ปกติแล้วคุณต้องการใช้กับซีแมนทิกส์ค่าเช่นเช่นค่า
คุณค่าคือสิ่งที่คุณสามารถเชื่อถือได้ว่าจะไม่เปลี่ยนแปลงหลังของคุณ ถ้าคุณเขียน: คุณไม่ต้องการที่จะเปลี่ยนจนกว่าคุณจะทำอะไรกับString str = someExpr();
str
String
ในฐานะที่Object
มีความหมายตามธรรมชาติเพื่อให้ได้ความหมายตามตัวอักษรมันจะต้องไม่เปลี่ยนรูป
ปัจจัยหนึ่งคือถ้าString
s ไม่แน่นอนวัตถุที่เก็บString
s จะต้องระมัดระวังในการจัดเก็บสำเนาเพื่อมิให้ข้อมูลภายในเปลี่ยนแปลงโดยไม่ต้องแจ้งให้ทราบล่วงหน้า เนื่องจากString
s เป็นชนิดดั้งเดิมที่ค่อนข้างเหมือนตัวเลขมันเป็นสิ่งที่ดีเมื่อเราสามารถปฏิบัติต่อพวกเขาราวกับว่าพวกเขาถูกส่งผ่านโดยค่าแม้ว่าพวกเขาจะผ่านการอ้างอิง (ซึ่งยังช่วยประหยัดหน่วยความจำ)
ฉันรู้ว่านี่เป็นชน แต่ ... พวกเขาไม่เปลี่ยนรูปจริงเหรอ? พิจารณาดังต่อไปนี้
public static unsafe void MutableReplaceIndex(string s, char c, int i)
{
fixed (char* ptr = s)
{
*((char*)(ptr + i)) = c;
}
}
...
string s = "abc";
MutableReplaceIndex(s, '1', 0);
MutableReplaceIndex(s, '2', 1);
MutableReplaceIndex(s, '3', 2);
Console.WriteLine(s); // Prints 1 2 3
คุณสามารถทำให้เป็นส่วนขยายได้
public static class Extensions
{
public static unsafe void MutableReplaceIndex(this string s, char c, int i)
{
fixed (char* ptr = s)
{
*((char*)(ptr + i)) = c;
}
}
}
ซึ่งทำให้งานต่อไปนี้
s.MutableReplaceIndex('1', 0);
s.MutableReplaceIndex('2', 1);
s.MutableReplaceIndex('3', 2);
สรุป: พวกเขาอยู่ในสถานะไม่เปลี่ยนรูปซึ่งเป็นที่รู้จักกันโดยคอมไพเลอร์ จากสาเหตุข้างต้นจะใช้กับสตริง. NET เท่านั้นเนื่องจาก Java ไม่มีพอยน์เตอร์ อย่างไรก็ตามสตริงสามารถเปลี่ยนแปลงได้ทั้งหมดโดยใช้พอยน์เตอร์ใน C # ไม่ใช่วิธีที่จะใช้พอยน์เตอร์มีการใช้งานจริงหรือใช้อย่างปลอดภัย มันเป็นไปได้อย่างไรก็ตามจึงดัดกฎ "ไม่แน่นอน" ทั้งหมด โดยปกติคุณไม่สามารถแก้ไขดัชนีของสตริงได้โดยตรงและนี่เป็นวิธีเดียวเท่านั้น มีวิธีที่สิ่งนี้สามารถป้องกันได้โดยไม่อนุญาตให้ตัวชี้อินสแตนซ์ของสตริงหรือทำสำเนาเมื่อสตริงถูกชี้ไป แต่ไม่ได้ทำซึ่งทำให้สตริงใน C # ไม่เปลี่ยนรูปทั้งหมด
สำหรับวัตถุประสงค์มากที่สุดเป็น "สตริง" จะ (ใช้ / ถือว่าเป็น / ความคิดของการ / สันนิษฐานว่าจะเป็น) มีความหมายหน่วยอะตอม เช่นเดียวกับตัวเลข
คุณควรรู้ว่าทำไม แค่คิดเกี่ยวกับมัน
ฉันเกลียดที่จะพูด แต่น่าเสียดายที่เรากำลังถกเถียงกันเรื่องนี้เพราะภาษาของเราแย่และเรากำลังพยายามใช้คำเดียวสายอักขระเพื่ออธิบายแนวคิดที่ซับซ้อนบริบทที่ตั้งอยู่หรือชั้นของวัตถุ
เราทำการคำนวณและการเปรียบเทียบด้วย "สตริง" ซึ่งคล้ายกับวิธีที่เราทำกับตัวเลข หากสตริง (หรือจำนวนเต็ม) ไม่แน่นอนเราจะต้องเขียนรหัสพิเศษเพื่อล็อคค่าของพวกเขาในรูปแบบที่ไม่เปลี่ยนรูปแบบในท้องถิ่นเพื่อทำการคำนวณชนิดใด ๆ ได้อย่างน่าเชื่อถือ ดังนั้นจึงควรคิดถึงสตริงเหมือนตัวระบุตัวเลข แต่แทนที่จะเป็น 16, 32, หรือ 64 บิตยาวมันอาจยาวหลายร้อยบิต
เมื่อมีคนพูดว่า "สตริง" เราทุกคนต่างนึกถึงสิ่งต่าง ๆ ผู้ที่คิดว่ามันเป็นเพียงชุดของตัวละครโดยไม่มีจุดประสงค์เป็นพิเศษแน่นอนว่าจะมีคนตกใจเมื่อมีคนตัดสินใจว่าพวกเขาไม่ควรจัดการกับตัวละครเหล่านั้นได้ แต่คลาส "string" ไม่ได้เป็นเพียงอาเรย์ของอักขระ มันเป็นไม่ได้STRING
char[]
มีสมมติฐานพื้นฐานบางอย่างเกี่ยวกับแนวคิดที่เราอ้างถึงว่าเป็น "สตริง" และโดยทั่วไปสามารถอธิบายได้ว่าเป็นหน่วยปรมาณูที่มีความหมายและมีความหมายของข้อมูลรหัสเช่นตัวเลข เมื่อผู้คนพูดถึง "จัดการสตริง" บางทีพวกเขากำลังพูดถึงการจัดการอักขระเพื่อสร้างสตริงและ StringBuilder ยอดเยี่ยมสำหรับสิ่งนั้น
พิจารณาสักครู่ว่ามันจะเป็นอย่างไรถ้ามีการเปลี่ยนแปลงสตริง ฟังก์ชัน API ต่อไปนี้อาจถูกหลอกให้ส่งคืนข้อมูลสำหรับผู้ใช้รายอื่นหากสตริงชื่อผู้ใช้ที่ไม่แน่นอนถูกแก้ไขโดยไม่ตั้งใจหรือไม่ได้ตั้งใจโดยเธรดอื่นในขณะที่ฟังก์ชันนี้กำลังใช้งานอยู่:
string GetPersonalInfo( string username, string password )
{
string stored_password = DBQuery.GetPasswordFor( username );
if (password == stored_password)
{
//another thread modifies the mutable 'username' string
return DBQuery.GetPersonalInfoFor( username );
}
}
ความปลอดภัยไม่ได้เกี่ยวกับ 'การควบคุมการเข้าถึง' แต่ยังเกี่ยวกับ 'ความปลอดภัย' และ 'การรับประกันความถูกต้อง' หากวิธีการไม่สามารถเขียนได้อย่างง่ายดายและขึ้นอยู่กับการคำนวณหรือการเปรียบเทียบที่เชื่อถือได้ง่ายก็จะไม่ปลอดภัยที่จะเรียกมัน แต่มันจะปลอดภัยที่จะถามคำถามเกี่ยวกับภาษาการเขียนโปรแกรมเอง
unsafe
) หรือเพียงแค่ผ่านการสะท้อน (คุณสามารถรับข้อมูลพื้นฐานได้อย่างง่ายดาย) นี้จะทำให้จุดบนโมฆะการรักษาความปลอดภัยเป็นใครที่จงใจต้องการที่จะเปลี่ยนสตริงสามารถทำได้ค่อนข้างง่าย อย่างไรก็ตามมันให้ความปลอดภัยแก่โปรแกรมเมอร์: ถ้าคุณไม่ทำอะไรเป็นพิเศษสตริงนั้นจะไม่เปลี่ยนไม่ได้ (แต่ไม่ใช่ threadsafe!)
การเปลี่ยนไม่ได้นั้นไม่เกี่ยวข้องกับความปลอดภัยอย่างใกล้ชิด อย่างน้อยที่สุดใน. NET คุณจะได้รับSecureString
คลาส
แก้ไขในภายหลัง: ใน Java คุณจะพบGuardedString
การใช้งานที่คล้ายกัน
มันเป็นการแลกเปลี่ยน String
เข้าสู่กลุ่มString
และเมื่อคุณสร้างหลาย ๆ รายการเหมือนกันString
พวกเขาแชร์หน่วยความจำเดียวกัน นักออกแบบคิดว่าเทคนิคการบันทึกหน่วยความจำนี้จะทำงานได้ดีสำหรับกรณีทั่วไปเนื่องจากโปรแกรมมักจะบดทับสายเดียวกันเป็นจำนวนมาก
ข้อเสียคือการต่อข้อมูลทำให้String
s พิเศษจำนวนมากเป็นเพียงการนำส่งและกลายเป็นขยะจริง ๆ แล้วส่งผลเสียต่อประสิทธิภาพของหน่วยความจำ คุณมีStringBuffer
และStringBuilder
(ใน Java StringBuilder
ยังอยู่ใน. NET) เพื่อใช้ในการรักษาหน่วยความจำในกรณีเหล่านี้
String
s ใน Java นั้นไม่เปลี่ยนรูปคุณสามารถเปลี่ยนค่าของมันโดยใช้การสะท้อนและหรือการโหลดคลาส คุณไม่ควรขึ้นอยู่กับคุณสมบัตินั้นเพื่อความปลอดภัย สำหรับตัวอย่างดู: Magic Trick In Java
การเปลี่ยนไม่ได้เป็นสิ่งที่ดี ดู Java ที่มีประสิทธิภาพ หากคุณต้องคัดลอกสตริงทุกครั้งที่คุณผ่านมันจะเป็นรหัสที่ผิดพลาดได้ง่ายมาก นอกจากนี้คุณยังมีความสับสนว่าการแก้ไขใดมีผลต่อการอ้างอิง ในลักษณะเดียวกับที่ Integer ต้องไม่เปลี่ยนรูปให้ทำตัวเหมือน int สตริงจะต้องทำตัวเหมือนไม่เปลี่ยนรูปเพื่อให้เหมือนดั่งดั้งเดิม ใน C ++ ผ่านสตริงโดยค่าทำสิ่งนี้โดยไม่ต้องพูดถึงอย่างชัดเจนในซอร์สโค้ด
มีข้อยกเว้นสำหรับเกือบทุกกฎ:
using System;
using System.Runtime.InteropServices;
namespace Guess
{
class Program
{
static void Main(string[] args)
{
const string str = "ABC";
Console.WriteLine(str);
Console.WriteLine(str.GetHashCode());
var handle = GCHandle.Alloc(str, GCHandleType.Pinned);
try
{
Marshal.WriteInt16(handle.AddrOfPinnedObject(), 4, 'Z');
Console.WriteLine(str);
Console.WriteLine(str.GetHashCode());
}
finally
{
handle.Free();
}
}
}
}
เป็นส่วนใหญ่ด้วยเหตุผลด้านความปลอดภัย มันเป็นเรื่องยากมากที่จะรักษาความปลอดภัยระบบถ้าคุณไม่สามารถไว้วางใจที่คุณString
s มี tamperproof