ทำไม String ถึงไม่เปลี่ยนรูปใน Java?


177

ฉันถูกถามในการสัมภาษณ์ว่าทำไม String ถึงไม่เปลี่ยนรูป

ฉันตอบแบบนี้:

เมื่อเราสร้างสตริงใน java อย่างเช่นString s1="hello";วัตถุจะถูกสร้างในstring pool (hello)และs1จะชี้ไปที่helloตอนนี้ถ้าเราทำString s2="hello";อีกครั้งวัตถุอื่นจะไม่ถูกสร้าง แต่s2จะชี้ไปที่hello เพราะJVMจะตรวจสอบก่อน ถ้าวัตถุเดียวกันนั้นมีอยู่ใน สตริงพูลหรือไม่หากไม่ปรากฏก็จะมีเพียงวัตถุใหม่เท่านั้น

ตอนนี้ถ้าสมมติว่า Java ช่วยให้สตริงแน่นอนแล้วถ้าเราเปลี่ยนs1ไปhello worldแล้วs2ค่ายังจะhello worldดังนั้น Java String จะไม่เปลี่ยนรูป

ร่างกายใดก็ได้โปรดบอกฉันว่าคำตอบของฉันถูกหรือผิด ?


46
ทำไมตอบยากเสมอ คำตอบที่ถูกต้องที่สุดน่าจะเป็น: เพราะนักออกแบบภาษาคิดว่ามันเป็นความคิดที่ดี
Keppil

1
ดูเพิ่มเติมคำตอบนี้

3
คำตอบของคุณไม่ตรงประเด็น C ++ std::stringนั้นไม่แน่นอน แต่ก็มีกลุ่มสตริงด้วยเช่นกัน (ดีกว่าถูกกว่าคือกลุ่มอาร์เรย์อักขระ)
Siyuan Ren

1
@ rocking บอกตามตรงไม่ว่าจะถูกหรือไม่ก็ขึ้นอยู่กับว่าพวกเขาอ่านมันอย่างไร สิ่งที่เป็น, Java สามารถมีสระว่ายน้ำสตริงเพราะสตริงไม่เปลี่ยนรูป หากพวกเขาตัดสินใจที่จะทำให้สตริงที่ไม่แน่นอนจากนั้นพวกเขาจะไม่ได้ใช้สระว่ายน้ำสตริง; ดังนั้นจึงอาจไม่ถูกต้องที่จะพูดว่า "string pool ดังนั้นสตริงที่ไม่เปลี่ยนรูป"; มันเป็นมากกว่าวิธีอื่น ๆ เหตุผลสำหรับการเลือกสายไม่เปลี่ยนรูปที่ระบุไว้ด้านล่างและสระว่ายน้ำสตริงเป็นกลยุทธ์ในการทำงานเพราะการที่ ถึงกระนั้นคำตอบของคุณไม่ถูกต้องแต่ดูเหมือนจะไม่สมบูรณ์ คุณเพียงแค่ต้องรอและดูว่าพวกเขาพูดอะไร
Jason C

34
ฉันไม่เข้าใจว่าทำไมคำถามนี้จึงถูกปิด คำตอบที่เกี่ยวข้องควรไม่ได้เกี่ยวกับ Java และไม่ได้อยู่ที่เรื่องหลักของคำถามนี้ซึ่งก็คือ "ทำไม" สำหรับฉันนี่เป็นหนึ่งในกรณีของชุมชนที่ขาดความรับผิดชอบที่ทำตามคำถามที่พวกเขาไม่รู้อะไรเลย ฉันได้เสนอชื่อให้เปิดใหม่อีกครั้ง
Edwin Dalorzo

คำตอบ:


163

String ไม่เปลี่ยนรูปได้จากหลายสาเหตุต่อไปนี้เป็นบทสรุป:

  • ความปลอดภัย : โดยทั่วไปพารามิเตอร์จะแสดงStringในการเชื่อมต่อเครือข่าย, URL การเชื่อมต่อฐานข้อมูล, ชื่อผู้ใช้ / รหัสผ่านเป็นต้นหากสามารถเปลี่ยนแปลงได้พารามิเตอร์เหล่านี้อาจเปลี่ยนแปลงได้ง่าย
  • การซิงโครไนซ์และการทำงานพร้อมกัน: การทำให้ String ไม่เปลี่ยนรูปแบบโดยอัตโนมัติทำให้เธรดนั้นปลอดภัยและแก้ไขปัญหาการซิงโครไนซ์
  • การแคช : เมื่อคอมไพเลอร์ปรับแต่งอ็อบเจกต์ String ของคุณให้ดีที่สุดจะเห็นว่าหากวัตถุสองชิ้นมีค่าเท่ากัน (a = "test" และ b = "test") ดังนั้นคุณต้องมีเพียงหนึ่งสตริงวัตถุเท่านั้น (สำหรับทั้ง a และ b ชี้ไปที่วัตถุเดียวกัน)
  • การโหลดคลาส : Stringใช้เป็นอาร์กิวเมนต์สำหรับการโหลดคลาส หากไม่แน่นอนอาจส่งผลให้มีการโหลดคลาสที่ไม่ถูกต้อง (เนื่องจากวัตถุที่ไม่แน่นอนสามารถเปลี่ยนสถานะได้)

ดังที่กล่าวไปแล้วความไม่สามารถเปลี่ยนได้Stringเพียงหมายความว่าคุณไม่สามารถเปลี่ยนแปลงได้โดยใช้ API สาธารณะ ในความเป็นจริงคุณสามารถข้าม API ปกติโดยใช้การไตร่ตรอง ดูคำตอบที่นี่

ในตัวอย่างของคุณถ้าStringไม่แน่นอนให้พิจารณาตัวอย่างต่อไปนี้:

  String a="stack";
  System.out.println(a);//prints stack
  a.setValue("overflow");
  System.out.println(a);//if mutable it would print overflow

14
จะส่งผลกระทบต่อความปลอดภัยได้อย่างไร?
Archit Maheshwari

2
มีใครช่วยอธิบายการโหลดคลาสด้วยตัวอย่างถ้าทำได้
Viraj

6
เกี่ยวกับความปลอดภัยหากฉันสนใจที่จะเปลี่ยนพารามิเตอร์การเชื่อมต่อมันจะตรงไปตรงมาในเวลาทำงาน (ด้วยดีบักเกอร์ ฯลฯ ) เกี่ยวกับการโหลดคลาสหากStringไม่แน่นอนจากนั้นตัวโหลดคลาสจะใช้สตริงที่ส่งผ่านทำสำเนาและไม่เปลี่ยนสำเนา เมื่อคิดถึงปัญหาเกี่ยวกับjava.lang.Strings ที่ไม่แน่นอนให้คิดว่า C ++ แก้ปัญหานี้อย่างไร (เนื่องจากมีstd::strings ที่ไม่แน่นอน
การแก้ไขที่มี จำกัด

เกี่ยวกับความปลอดภัยสตริงที่ไม่แน่นอนสามารถเปลี่ยนแปลงได้อย่างไรเมื่อโปรแกรมทำงาน?
MasterJoe2

เนื่องจาก String ไม่สามารถเปลี่ยนแปลงได้แฮชโค้ดของมันจะถูกแคชในเวลาที่สร้างและไม่จำเป็นต้องคำนวณอีกครั้ง
Abdul Alim Shakir

45

ผู้พัฒนา Java ตัดสินใจว่า Strings ไม่เปลี่ยนรูปเนื่องจากการออกแบบด้านประสิทธิภาพและความปลอดภัยต่อไปนี้

Design Strings ถูกสร้างขึ้นในพื้นที่หน่วยความจำพิเศษใน java heap ที่รู้จักกันในชื่อ "String Intern pool" ในขณะที่คุณสร้าง String ใหม่ (ไม่ใช่ในกรณีของการใช้ String () Constructor หรือฟังก์ชั่น String อื่น ๆ ที่ใช้ Constructor String () ภายในสำหรับการสร้างวัตถุ String ใหม่; String () Constructor สร้างเสมอสตริงใหม่ในสระเว้นแต่เรา เรียกใช้ตัวแปรmethod () ) ซึ่งค้นหาพูลเพื่อตรวจสอบว่ามีอยู่แล้วหรือไม่ ถ้ามันมีอยู่แล้วส่งคืนการอ้างอิงของวัตถุสตริงที่มีอยู่ ถ้าสตริงไม่เปลี่ยนรูปการเปลี่ยนสตริงด้วยการอ้างอิงเดียวจะนำไปสู่ค่าที่ไม่ถูกต้องสำหรับการอ้างอิงอื่น

ตามนี้บทความเกี่ยวกับ DZone:

Security String ถูกใช้อย่างกว้างขวางเป็นพารามิเตอร์สำหรับคลาส Java จำนวนมากเช่นการเชื่อมต่อเครือข่ายการเปิดไฟล์และอื่น ๆ หาก String นั้นไม่เปลี่ยนรูปไม่ได้การเชื่อมต่อหรือไฟล์จะเปลี่ยนไปและนำไปสู่ภัยคุกคามความปลอดภัยที่ร้ายแรง สตริงที่ไม่แน่นอนอาจทำให้เกิดปัญหาความปลอดภัยใน Reflection เช่นกันเนื่องจากพารามิเตอร์เป็นสตริง

ประสิทธิภาพ การแฮชโค้ดของสตริงมักใช้ใน Java ตัวอย่างเช่นใน HashMap การรับประกันแบบไม่เปลี่ยนเปลี่ยนที่ hashcode จะเหมือนเดิมเสมอเพื่อให้สามารถแคชได้โดยไม่ต้องกังวลกับการเปลี่ยนแปลงนั่นหมายความว่าไม่จำเป็นต้องคำนวณ hashcode ทุกครั้งที่ใช้


7
ความเข้าใจเกี่ยวกับพูลสตริงของคุณไม่ถูกต้อง ค่าคงที่สตริงถูกสร้างขึ้นในพูลฝึกงาน แต่เป็นไปได้อย่างสมบูรณ์แบบที่จะมีวัตถุสตริงมากกว่าหนึ่งรายการที่มีข้อความเดียวกันฉันยอมรับว่าสตริงที่ไม่เปลี่ยนรูปจะช่วยให้การรวมกำไร
Jon Skeet

@JonSkeet คุณพูดถูก String s1 = new String ("test"); คำสั่งสร้างค่าคงที่สตริงใหม่ในพูลฝึกงานยกเว้นว่าเราเรียกเมธอดฝึกงาน () ขอบคุณสำหรับความรู้ของฉันที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับสระว่ายน้ำของสตริง
Alex Mathew

2
มันเป็นมากกว่าแค่การใช้ตัวสร้างสตริง - เกือบทุกอย่างที่สร้างสตริงใหม่เช่นสตริงย่อย, แยก, concat ฯลฯ จะสร้างสตริงใหม่ ค่าคงที่เวลารวบรวมเป็นกรณีพิเศษที่นี่ไม่ปกติ ...
จอน Skeet

สตริงย่อย @JonSkeet (), concat (), replace () ฯลฯ ใช้ภายในตัวสร้างสตริงสำหรับการสร้างวัตถุสตริงใหม่ ขอบคุณสำหรับการปรับปรุงคำตอบของฉัน
Alex Mathew

2
@JonSkeet - คำตอบทั้งหมดเหล่านี้บอกว่าการเปลี่ยนแปลงไม่ได้ช่วยเพิ่ม "ความปลอดภัย" แต่ไม่อธิบายว่าอย่างไร พวกเขาทั้งหมดเชื่อมโยงไปยังบทความ dzone คลุมเครือซึ่งไม่ได้ช่วยเช่นกัน คำตอบ / การเชื่อมโยงไม่ได้อธิบายถึงวิธีการเปลี่ยนแปลงสตริงที่ไม่แน่นอนเมื่อมีการเรียกใช้รหัส คุณช่วยอธิบายได้มั้ย
MasterJoe2

25

เราไม่สามารถแน่ใจได้ว่านักออกแบบ Java กำลังคิดอะไรอยู่ในขณะที่ออกแบบStringแต่เราสามารถสรุปเหตุผลเหล่านี้ได้จากข้อดีที่เราไม่สามารถเปลี่ยนแปลงได้ของสตริง

1. การดำรงอยู่ของ String Constant Pool

ดังที่อธิบายไว้ในWhy String ถูกเก็บไว้ในบทความString Constant Poolทุกแอปพลิเคชันสร้างวัตถุสตริงมากเกินไปและเพื่อบันทึก JVM จากการสร้างวัตถุสตริงจำนวนมากก่อนแล้วจึงเก็บรวบรวมขยะ JVM เก็บวัตถุสตริงทั้งหมดในพื้นที่หน่วยความจำแยกต่างหากที่เรียกว่า String ค่าคงที่สระว่ายน้ำและนำวัตถุจากสระว่ายน้ำแคชนั้น

เมื่อใดก็ตามที่เราสร้างสตริงตัวอักษร JVM จะเห็นเป็นครั้งแรกว่าตัวอักษรนั้นมีอยู่ในสระน้ำคงที่หรือไม่และถ้ามีแล้วการอ้างอิงใหม่จะเริ่มชี้ไปที่วัตถุเดียวกันใน SCP

String a = "Naresh";
String b = "Naresh";
String c = "Naresh";

ในตัวอย่างข้างต้นวัตถุสตริงที่มีค่าNareshจะได้รับการสร้างขึ้นใน SCP เพียงครั้งเดียวและการอ้างอิงทั้งหมดa, b, cจะชี้ไปที่วัตถุเดียวกัน แต่ถ้าเราพยายามที่จะทำให้เกิดการเปลี่ยนแปลงในเช่นaa.replace("a", "")

จะเป็นการดีที่aควรจะมีค่าNreshแต่b, cควรจะยังคงไม่เปลี่ยนแปลงเพราะเป็นผู้ใช้สิ้นเราจะทำให้การเปลี่ยนแปลงaเท่านั้น และเรารู้ว่าa, b, cทั้งหมดจะถูกชี้วัตถุเดียวกันดังนั้นหากเราทำการเปลี่ยนแปลงในaคนอื่น ๆ นอกจากนี้ยังควรสะท้อนให้เห็นถึงการเปลี่ยนแปลง

แต่สตริงที่ไม่เปลี่ยนรูปจะช่วยให้เราประหยัดจากสถานการณ์นี้และเนื่องจากความไม่สามารถเปลี่ยนแปลงได้ของสตริงวัตถุวัตถุสตริงNareshจะไม่เปลี่ยนแปลง ดังนั้นเมื่อเราทำการเปลี่ยนแปลงใด ๆaแทนการเปลี่ยนแปลงในวัตถุสตริงNareshJVM สร้างวัตถุใหม่กำหนดให้aแล้วทำการเปลี่ยนแปลงในวัตถุนั้น

ดังนั้น String pool จึงมีความเป็นไปได้เพียงอย่างเดียวเนื่องจากความไม่สามารถเปลี่ยนได้ของ String และหาก String นั้นไม่สามารถเปลี่ยนรูปแบบได้ดังนั้นการแคชวัตถุสตริงและการนำกลับมาใช้ใหม่จะไม่มีความเป็นไปได้เพราะตัวแปรใด ๆ

และนั่นคือสาเหตุที่ JVM จัดการเป็นพิเศษและได้รับพื้นที่หน่วยความจำพิเศษ

2. ความปลอดภัยด้าย

วัตถุถูกเรียกว่า thread-safe เมื่อมีหลายเธรดกำลังทำงานอยู่ แต่ไม่มีวัตถุใดที่สามารถทำให้สถานะของมันเสียหายและวัตถุนั้นจะคงสถานะเดิมไว้สำหรับทุกเธรดในเวลาใดก็ได้

ในฐานะที่เราเป็นวัตถุที่ไม่เปลี่ยนรูปไม่สามารถแก้ไขได้โดยทุกคนหลังจากการสร้างซึ่งทำให้ทุกวัตถุที่ไม่เปลี่ยนรูปเป็นด้ายปลอดภัยโดยค่าเริ่มต้น เราไม่จำเป็นต้องใช้มาตรการความปลอดภัยของเธรดใด ๆ กับมันเช่นการสร้างวิธีการซิงโครไนซ์

ดังนั้นเนื่องจากวัตถุสตริงธรรมชาติที่ไม่เปลี่ยนรูปแบบของมันสามารถใช้ร่วมกันโดยหลายกระทู้และแม้ว่ามันจะได้รับการจัดการโดยหลายกระทู้มันจะไม่เปลี่ยนค่าของมัน

3. ความปลอดภัย

ในทุกแอปพลิเคชันเราต้องส่งความลับหลายอย่างเช่นชื่อผู้ใช้ \ รหัสผ่านของผู้ใช้ URL การเชื่อมต่อและโดยทั่วไปข้อมูลทั้งหมดนี้จะถูกส่งผ่านเป็นวัตถุสตริง

ตอนนี้สมมติว่า String จะไม่เปลี่ยนแปลงไม่ได้ในลักษณะนั้นมันจะก่อให้เกิดภัยคุกคามความปลอดภัยอย่างร้ายแรงต่อแอปพลิเคชันเนื่องจากค่าเหล่านี้ได้รับอนุญาตให้เปลี่ยนและหากได้รับอนุญาตแล้วสิ่งเหล่านี้อาจเปลี่ยนเนื่องจากรหัสที่เขียนผิดหรือบุคคลอื่น ๆ สามารถเข้าถึงการอ้างอิงตัวแปรของเรา

4. Class Loading

ตามที่กล่าวไว้ในการสร้างวัตถุผ่าน Reflection ใน Java ด้วยตัวอย่างเราสามารถใช้Class.forName("class_name")วิธีการโหลดคลาสในหน่วยความจำซึ่งเรียกวิธีการอื่น ๆ อีกครั้งเพื่อทำเช่นนั้น และแม้แต่ JVM ก็ใช้วิธีการเหล่านี้ในการโหลดคลาส

ClassLoaderแต่ถ้าคุณเห็นได้อย่างชัดเจนทุกวิธีการเหล่านี้ยอมรับชื่อชั้นเป็นวัตถุสตริงเพื่อให้สายที่ใช้ในการโหลดคลาสจาวาและเปลี่ยนไม่ได้ให้การรักษาความปลอดภัยที่ระดับที่ถูกต้องจะได้รับการโหลดโดย

สมมติว่า String จะไม่เปลี่ยนแปลงไม่ได้และเราพยายามโหลดjava.lang.Objectซึ่งเปลี่ยนเป็นorg.theft.OurObjectระหว่างและตอนนี้วัตถุทั้งหมดของเรามีพฤติกรรมที่ใครบางคนสามารถใช้กับสิ่งที่ไม่ต้องการ

5. การแคช HashCode

หากเรากำลังจะทำการดำเนินการที่เกี่ยวข้องกับการแปลงแป้นพิมพ์บนวัตถุใด ๆ เราจะต้องแทนที่hashCode()วิธีการและพยายามที่จะสร้าง hashcode ที่ถูกต้องโดยใช้สถานะของวัตถุ หากสถานะของวัตถุมีการเปลี่ยนแปลงซึ่งหมายความว่าแฮชโค้ดควรเปลี่ยนเช่นกัน

เนื่องจาก String ไม่สามารถเปลี่ยนแปลงได้ดังนั้นค่าหนึ่งในวัตถุสตริงจะไม่ถูกเปลี่ยนแปลงซึ่งหมายความว่าแฮชโค้ดของมันจะไม่เปลี่ยนแปลงซึ่งทำให้คลาส String มีโอกาสแคชแฮชโค้ดในระหว่างการสร้างวัตถุ

ใช่วัตถุ String เก็บรหัสแฮชในเวลาที่สร้างวัตถุซึ่งเป็นตัวเลือกที่ยอดเยี่ยมสำหรับการดำเนินการที่เกี่ยวข้องกับการแฮชเนื่องจาก hashcode ไม่จำเป็นต้องคำนวณอีกครั้งซึ่งช่วยให้เราประหยัดเวลา นี่คือเหตุผลที่ String ส่วนใหญ่ถูกใช้เป็นHashMapกุญแจ

อ่านข้อมูลเพิ่มเติมเกี่ยวกับทำไม String จะไม่เปลี่ยนรูปและรอบชิงชนะเลิศในชวา


1
เกี่ยวกับความปลอดภัย - ค่าสตริงที่เปลี่ยนแปลงได้สามารถเปลี่ยนแปลงในหน่วยความจำได้อย่างไร? บุคคลอื่นจะเข้าถึงการอ้างอิงตัวแปรของเราได้อย่างไร
MasterJoe2

มันไม่ได้เกี่ยวกับวิธีการเข้าถึงการอ้างอิงมันจะเกิดอะไรขึ้นถ้ามีคนเข้าถึงข้อมูลเหล่านั้น? ตามที่ระบุไว้ "ถ้า String ไม่ได้รับการเปลี่ยนแปลงไม่ได้ในลักษณะนั้นจะทำให้เกิดภัยคุกคามความปลอดภัยอย่างร้ายแรงต่อแอปพลิเคชันเนื่องจากค่าเหล่านี้ได้รับอนุญาตให้เปลี่ยนและหากได้รับอนุญาตแล้วสิ่งเหล่านี้อาจเปลี่ยนไปเนื่องจากรหัสที่เขียนผิดหรือบุคคลอื่น ๆ ใครสามารถเข้าถึงการอ้างอิงตัวแปรของเรา "
Naresh Joshi

วิธีการที่สำคัญที่นี่ เป็นไปได้ที่จะได้รับการเข้าถึงการอ้างอิงหรือไม่ ถ้าเป็นไปได้คุณสามารถตั้งชื่อเทคนิค 1-2 ข้อที่ใช้ในการทำสิ่งนั้นได้หรือไม่? หากเป็นไปไม่ได้จุดเกี่ยวกับความปลอดภัยจะไม่สามารถใช้ได้ ตัวอย่าง *** - ชื่อเทคนิคหนึ่งเพื่อโจมตีฐานข้อมูลของเว็บแอป -> SQL Injection คุณรู้เทคนิคใด ๆ เช่นนี้เพื่อโจมตีการอ้างอิงหรือไม่
MasterJoe2

ดังที่กล่าวไว้ "อาจเกิดขึ้นได้เนื่องจากรหัสที่เขียนผิดหรือการเปลี่ยนแปลงใด ๆ ที่กระทำโดยบุคคลอื่นที่สามารถเข้าถึงการอ้างอิงตัวแปรของเรา" เช่นสมมติว่าสตริงไม่แน่นอนและคุณกำลังเขียนวิธีการบางอย่างที่ใช้สตริงลับสตริงและอีกครั้งที่สตริงจะถูกส่งผ่านไปยังอีกหลายวิธีในระหว่างและหนึ่งในวิธีการเหล่านั้นไม่ได้เขียนโดยคุณและวิธีการที่ทำให้การเปลี่ยนแปลงบางอย่าง สตริงตอนนี้หลังจากเรียกวิธีการเหล่านี้ทั้งหมดควบคุมกลับวิธีการของคุณและคุณกำลังใช้สตริงที่อีกครั้ง แต่มันมีการเปลี่ยนแปลง
Naresh Joshi

2
กรุณาเปิดเผยพันธมิตรใด ๆและไม่ใช้เว็บไซต์เป็นวิธีการส่งเสริมเว็บไซต์ของคุณผ่านการโพสต์ ดูฉันจะเขียนคำตอบที่ดีได้อย่างไร .
Yvette

21

เหตุผลที่สำคัญที่สุดตามนี้บทความเกี่ยวกับ DZone:

String Constant Pool ... หากสตริงไม่แน่นอนการเปลี่ยนสตริงด้วยการอ้างอิงหนึ่งรายการจะนำไปสู่ค่าที่ไม่ถูกต้องสำหรับการอ้างอิงอื่น

ความปลอดภัย

String ใช้กันอย่างแพร่หลายเป็นพารามิเตอร์สำหรับคลาส Java จำนวนมากเช่นการเชื่อมต่อเครือข่ายการเปิดไฟล์ ฯลฯ หาก String ไม่สามารถเปลี่ยนรูปแบบได้การเชื่อมต่อหรือไฟล์จะเปลี่ยนไปและนำไปสู่การคุกคามด้านความปลอดภัยที่ร้ายแรง ...

หวังว่ามันจะช่วยคุณ


@ JasonC ฉันแค่อยากรู้ว่าคำตอบของฉันผิดหรือเปล่าฉันเข้าร่วมการสัมภาษณ์แล้วและรอผลถ้าคำตอบบอกพวกเขาถูกต้องฉันจะถูกเลือก
โยก

1
ตามความรู้ของฉันคำตอบของคุณถูกต้อง แต่ค่าเฉลี่ยไม่เปลี่ยนแปลงการอ้างอิงจะไม่เปลี่ยนตำแหน่งชี้ทั้งหมดที่ดีที่สุดสำหรับการสัมภาษณ์ของคุณ
JDGuide

1
หากยอมรับคะแนนของคุณ # 1 วัตถุทั้งหมดควรจะไม่เปลี่ยนรูป
nicomp

สวัสดี JDeveloper ฉันได้แก้ไขคำตอบของคุณเพื่อให้การระบุแหล่งที่มาที่เหมาะสมกับแหล่งที่มาของคำตอบของคุณ อย่าลืมใช้เครื่องหมายคำพูดบล็อกสำหรับสำเนาของเนื้อหาทุกคำ ขอบคุณ!
NickL

บทความ DZone มีข้อผิดพลาดที่สำคัญเกี่ยวกับการทำงานของ Strign pool มันเป็นเพียงค่าคงที่ Ergoเหตุผลดังกล่าวไม่ถูกต้อง
มาร์ควิสแห่ง Lorne

4

ฉันอ่านโพสต์นี้เพราะเหตุใด String จึงไม่เปลี่ยนรูปหรือสุดท้ายใน Javaและคิดว่าต่อไปนี้อาจเป็นเหตุผลที่สำคัญที่สุด:

String จะไม่เปลี่ยนรูปในชวาเพราะวัตถุ String จะถูกเก็บไว้ชั่วคราวในสระว่ายน้ำสตริง เนื่องจากตัวอักษรสตริงที่แคชจะใช้ร่วมกันระหว่างไคลเอนต์หลายตัวจึงมีความเสี่ยงอยู่เสมอซึ่งการกระทำของลูกค้ารายหนึ่งจะส่งผลกระทบต่อลูกค้ารายอื่นทั้งหมด


1

คุณพูดถูก Stringใน java ใช้แนวคิดของString Poolตัวอักษร เมื่อสตริงถูกสร้างขึ้นและหากสตริงนั้นมีอยู่แล้วในพูลการอ้างอิงของสตริงที่มีอยู่จะถูกส่งคืนแทนที่จะสร้างวัตถุใหม่และส่งคืนการอ้างอิงถ้าสตริงนั้นไม่เปลี่ยนรูปได้การเปลี่ยนสตริงด้วยการอ้างอิงเดียวจะ นำไปสู่ค่าที่ไม่ถูกต้องสำหรับการอ้างอิงอื่น ๆ

ฉันจะเพิ่มอีกสิ่งหนึ่งเนื่องจากStringไม่เปลี่ยนรูปมันปลอดภัยสำหรับเธรดหลายตัวและอินสแตนซ์ของสตริงเดียวสามารถแชร์ข้ามเธรดที่แตกต่างกันได้ thread safeหลีกเลี่ยงปัญหานี้การใช้งานของการประสานเพื่อความปลอดภัยด้ายสตริงโดยปริยาย


0

คลาส String FINALหมายความว่าคุณไม่สามารถสร้างคลาสใด ๆ เพื่อสืบทอดและเปลี่ยนโครงสร้างพื้นฐานและทำให้ Sting ไม่แน่นอน

ตัวแปรอินสแตนซ์ของอีกสิ่งหนึ่งและวิธีการของคลาสสตริงที่ให้ไว้นั้นคุณไม่สามารถเปลี่ยนStringวัตถุเมื่อสร้าง

เหตุผลที่คุณเพิ่มไม่ทำให้ String ไม่เปลี่ยนรูปเลยสิ่งนี้บอกว่าการจัดเก็บสตริงในฮีปมีอะไรบ้างนอกจากนี้สตริงพูลยังสร้างความแตกต่างอย่างมากในประสิทธิภาพ


11
ถ้าคลาสที่ประกาศเป็นขั้นสุดท้ายหมายความว่าคลาสนั้นไม่สามารถสืบทอดได้ แต่ก็ไม่ได้หมายความว่าฟิลด์อินสแตนซ์ของคลาสนั้นไม่สามารถเปลี่ยนแปลงได้ดังนั้นคลาสจึงไม่เปลี่ยนรูป
Dmitry Bychenko

@ Zeeshan: ชั้นเรียนตัวอย่างที่คุณให้นั้นไม่เปลี่ยนรูปทั้งหมด
Siyuan Ren

0

String ถูกกำหนดให้ไม่เปลี่ยนรูปโดยระบบ Sun micro เนื่องจากสตริงสามารถใช้เพื่อเก็บเป็นคีย์ในการรวบรวมแผนที่ StringBuffer ไม่แน่นอนนั่นคือเหตุผลที่มันไม่สามารถใช้เป็นกุญแจสำคัญในวัตถุแผนที่


0

เหตุผลที่สำคัญที่สุดของสตริงที่ทำให้ไม่เปลี่ยนรูปแบบใน Java คือการพิจารณาความปลอดภัย ถัดไปจะเป็นแคช

ฉันเชื่อว่ามีเหตุผลอื่นที่ให้ไว้ที่นี่เช่นประสิทธิภาพการทำงานพร้อมกันการออกแบบและกลุ่มของสตริงตามมาจากความจริงที่ว่า String ทำให้ไม่เปลี่ยนรูป สำหรับเช่น String Pool สามารถสร้างได้เนื่องจาก String ไม่มีการเปลี่ยนแปลงและไม่ใช่วิธีอื่น

ตรวจสอบบันทึกการสัมภาษณ์กอสลิงที่นี่

จากมุมมองเชิงกลยุทธ์พวกเขามักจะมีปัญหามากขึ้นฟรี และมักจะมีสิ่งที่คุณสามารถทำกับสิ่งที่ไม่สามารถเปลี่ยนแปลงได้ที่คุณไม่สามารถทำกับสิ่งที่ไม่แน่นอนเช่นแคชผลลัพธ์ หากคุณส่งสตริงไปยังวิธีการเปิดไฟล์หรือถ้าคุณส่งสตริงไปยังตัวสร้างสำหรับฉลากในส่วนติดต่อผู้ใช้ในบาง APIs (เช่นใน Windows APIs จำนวนมาก) คุณจะส่งผ่านอาร์เรย์ของอักขระ ผู้รับของวัตถุนั้นมีการคัดลอกเพราะพวกเขาไม่รู้อะไรเกี่ยวกับอายุการเก็บรักษาของมัน และพวกเขาไม่รู้ว่าเกิดอะไรขึ้นกับวัตถุไม่ว่ามันจะเปลี่ยนไปหรือไม่

คุณเกือบถูกบังคับให้ทำซ้ำวัตถุเพราะคุณไม่รู้ว่าคุณได้เป็นเจ้าของมันหรือไม่ และสิ่งหนึ่งที่ดีเกี่ยวกับวัตถุที่เปลี่ยนแปลงไม่ได้คือคำตอบคือ "ใช่แน่นอนคุณต้องทำ" เนื่องจากคำถามเกี่ยวกับความเป็นเจ้าของผู้มีสิทธิ์ในการเปลี่ยนแปลงไม่มีอยู่

สิ่งหนึ่งที่บังคับให้ Strings ไม่เปลี่ยนรูปก็คือความปลอดภัย คุณมีวิธีการเปิดไฟล์ คุณส่งสตริงให้มัน จากนั้นจะทำการตรวจสอบความถูกต้องทุกชนิดก่อนที่จะทำการเรียกใช้ระบบปฏิบัติการ หากคุณจัดการที่จะทำบางสิ่งบางอย่างที่กลายพันธุ์ String อย่างมีประสิทธิภาพหลังจากการตรวจสอบความปลอดภัยและก่อนการเรียกใช้ระบบปฏิบัติการแล้วบูมคุณเข้ามา แต่ Strings นั้นไม่เปลี่ยนรูปดังนั้นการโจมตีแบบนี้จะไม่ทำงาน ตัวอย่างที่แม่นยำนั้นเป็นสิ่งที่เรียกร้องอย่างแท้จริงว่า Strings นั้นไม่เปลี่ยนรูป


0

นอกจากคำตอบที่ยอดเยี่ยมฉันต้องการเพิ่มบางจุด เช่นเดียวกับสตริง Array มีการอ้างอิงถึงการเริ่มต้นของอาร์เรย์ดังนั้นหากคุณสร้างสองอาร์เรย์arr1และarr2และทำสิ่งarr2 = arr1นี้จะทำให้การอ้างอิงarr2เหมือนกันarr1ดังนั้นการเปลี่ยนค่าในหนึ่งของพวกเขาจะส่งผลให้เกิดการเปลี่ยนแปลงอื่น ๆ เช่น

public class Main {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4};
        int[] b = a;
        a[0] = 8;
        b[1] = 7;
        System.out.println("A: " + a[0] + ", B: " + b[0]);
        System.out.println("A: " + a[1] + ", B: " + b[1]);
        //outputs
        //A: 8, B: 8
        //A: 7, B: 7
    }
}

ไม่เพียง แต่มันจะทำให้เกิดข้อบกพร่องในรหัส แต่ยังสามารถ (และจะ) ถูกโจมตีโดยผู้ใช้ที่เป็นอันตราย สมมติว่าคุณมีระบบที่เปลี่ยนรหัสผ่านของผู้ดูแลระบบ ผู้ใช้ต้องแรกใส่newPasswordแล้วoldPasswordถ้าoldPasswordเป็นเช่นเดียวกับการเปลี่ยนแปลงโปรแกรมรหัสผ่านโดยadminPass adminPass = newPasswordสมมติว่ารหัสผ่านใหม่มีการอ้างอิงเช่นเดียวกับรหัสผ่านของผู้ดูแลระบบดังนั้นโปรแกรมเมอร์ที่ไม่ดีอาจสร้างtempตัวแปรเพื่อเก็บรหัสผ่านของผู้ดูแลระบบไว้ก่อนที่ผู้ใช้จะป้อนข้อมูลหากoldPasswordเท่ากับจะtempเปลี่ยนรหัสผ่านมิฉะนั้นadminPass = temp. มีคนรู้ว่าสามารถป้อนรหัสผ่านใหม่ได้อย่างง่ายดายและไม่เคยป้อนรหัสผ่านเก่าและ abracadabra เขามีสิทธิ์เข้าถึงแบบผู้ดูแลระบบ อีกสิ่งหนึ่งที่ฉันไม่เข้าใจเมื่อเรียนรู้เกี่ยวกับสตริงทำไม JVM ไม่สร้างสตริงใหม่สำหรับทุกวัตถุและมีสถานที่พิเศษในหน่วยความจำสำหรับมันและคุณสามารถทำได้โดยใช้new String("str");เหตุผลที่คุณไม่ต้องการใช้อยู่เสมอnewคือ เพราะมันไม่ได้เป็นหน่วยความจำที่มีประสิทธิภาพและเป็นที่ช้าลงในกรณีส่วนใหญ่อ่านรายละเอียดเพิ่มเติม


0

ถ้าHELLOเป็น String ของคุณแล้วคุณจะไม่สามารถเปลี่ยนไปHELLO HILLOคุณสมบัตินี้เรียกว่าคุณสมบัติไม่เปลี่ยนรูป

คุณสามารถมีตัวแปร String ของตัวชี้หลายตัวชี้ HELLO String

แต่ถ้า HELLO เป็นถ่าน Array คุณสามารถเปลี่ยน HELLO เป็น HILLO ได้ เช่น,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

ตอบ:

ภาษาการเขียนโปรแกรมมีตัวแปรข้อมูลที่เปลี่ยนแปลงไม่ได้ดังนั้นจึงสามารถใช้เป็นคีย์ในคู่ของคีย์, คู่ของค่า ตัวแปร String จะถูกใช้เป็นคีย์ / ดัชนีดังนั้นพวกเขาจะไม่เปลี่ยนรูป


-1

จากSecurityมุมมองเราสามารถใช้ตัวอย่างการปฏิบัตินี้:

DBCursor makeConnection(String IP,String PORT,String USER,String PASS,String TABLE) {

    // if strings were mutable IP,PORT,USER,PASS can be changed by validate function
    Boolean validated = validate(IP,PORT,USER,PASS);

    // here we are not sure if IP, PORT, USER, PASS changed or not ??
    if (validated) {
         DBConnection conn = doConnection(IP,PORT,USER,PASS);
    }

    // rest of the code goes here ....
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.