เหตุใดคลาส String จึงถูกประกาศเป็นขั้นสุดท้ายใน Java


141

จากเมื่อฉันได้เรียนรู้ว่าชั้นเรียนjava.lang.Stringได้รับการประกาศเป็นขั้นสุดท้ายใน Java ฉันสงสัยว่าทำไมเป็นเช่นนั้น ฉันไม่พบคำตอบใด ๆ ในตอนนี้ แต่โพสต์นี้: จะสร้างแบบจำลองของคลาส String ใน Java ได้อย่างไร ทำให้ฉันนึกถึงการค้นหาของฉัน

แน่นอนว่า String มีฟังก์ชั่นทั้งหมดที่ฉันต้องการและฉันไม่เคยคิดถึงการดำเนินการใด ๆ ที่ต้องการส่วนเสริมของคลาส String แต่คุณก็ยังไม่มีทางรู้ว่าใครบางคนอาจต้องการ!

ดังนั้นไม่มีใครรู้ว่าเจตนาของนักออกแบบคืออะไรเมื่อพวกเขาตัดสินใจที่จะทำให้มันเป็นที่สิ้นสุด?


ขอบคุณสำหรับคำตอบของคุณโดยเฉพาะ TrueWill, Bruno Reis และ Thilo! ฉันหวังว่าฉันจะเลือกได้มากกว่าหนึ่งคำตอบว่าเป็นคำตอบที่ดีที่สุด แต่น่าเสียดายที่ ... !
Alex Ntousias

1
นอกจากนี้ให้พิจารณาการเพิ่มจำนวนของ "โอ้ฉันแค่ต้องการวิธีการใช้ประโยชน์อีกสองสามอย่างในโครงการ String" ซึ่งจะปรากฏขึ้น - ซึ่งทั้งหมดไม่สามารถใช้ Strings ซึ่งกันและกันไม่ได้เพราะเป็นคลาสที่แตกต่างกัน
Thorbjørn Ravn Andersen

ขอบคุณสำหรับคำตอบนี้มีประโยชน์มาก ตอนนี้เรามีข้อเท็จจริงสองข้อแล้ว สตริงเป็นคลาสสุดท้ายและไม่เปลี่ยนรูปเนื่องจากไม่สามารถเปลี่ยนแปลงได้ แต่สามารถอ้างอิงไปยังวัตถุอื่นได้ แต่สิ่งที่เกี่ยวกับ: - String a = new String ("test1"); จากนั้น s = "test2"; ถ้า String เป็นอ็อบเจกต์ระดับสุดท้ายแล้วจะสามารถแก้ไขได้อย่างไร? ฉันจะใช้วัตถุสุดท้ายที่ปรับเปลี่ยนแล้วได้อย่างไร โปรดให้ฉันถ้าฉันถามอะไรผิด
Suresh Sharma

คุณสามารถดูดีนี้บทความ
Aniket Thakur

4
สิ่งหนึ่งที่เราหลีกเลี่ยงไม่ได้ใน Java คือ "ทุกคนมีคลาสย่อยของ String ของตัวเองด้วยวิธีการพิเศษมากมาย
Thorbjørn Ravn Andersen

คำตอบ:


88

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

ข้อดีอย่างหนึ่งของวัตถุที่ไม่เปลี่ยนรูปนั้นคือ

คุณสามารถแบ่งปันรายการที่ซ้ำกันโดยการชี้ไปที่อินสแตนซ์เดียว

(จากที่นี่ )

หาก String ไม่สุดท้ายคุณสามารถสร้างคลาสย่อยและมีสองสายที่มีลักษณะเหมือนกันเมื่อ "เห็นเป็นสตริง" แต่ที่แตกต่างกันจริง


70
ถ้าไม่มีการเชื่อมต่อระหว่างคลาสสุดท้ายและวัตถุที่ไม่เปลี่ยนรูปแบบที่ฉันไม่เห็นฉันไม่เห็นว่าคำตอบของคุณเกี่ยวข้องกับคำถามอย่างไร
sepp2k

9
เพราะถ้ายังไม่ถึงขั้นสุดท้ายคุณสามารถส่ง StringChild ไปยังเมธอดบางตัวเป็น String Param และมันอาจไม่แน่นอน (เนื่องจากสถานะคลาสย่อยเปลี่ยนแปลง)
helios

4
ว้าว! downvotes? คุณไม่เข้าใจว่า subclassing เกี่ยวข้องกับสิ่งที่ไม่เปลี่ยนแปลงหรือไม่ ฉันขอขอบคุณคำอธิบายเกี่ยวกับปัญหาที่เกิดขึ้น
Bruno Reis

7
@Bruno, re: downvotes: ฉันไม่ได้ลงคะแนนให้คุณ แต่คุณสามารถเพิ่มประโยคเกี่ยวกับวิธีการป้องกัน subclasses บังคับใช้ไม่ได้ ตอนนี้มันเป็นคำตอบครึ่งหนึ่ง
Thilo

12
@BrunoReis - พบบทความที่ดีที่คุณสามารถเชื่อมโยงไปที่มีการให้สัมภาษณ์กับเจมส์กอสลิง (ผู้สร้างของ Java) ที่เขาพูดคุยสั้น ๆ เกี่ยวกับหัวข้อนี้ที่นี่ นี่เป็นตัวอย่างที่น่าสนใจ: "สิ่งหนึ่งที่บังคับให้ Strings ไม่เปลี่ยนรูปก็คือความปลอดภัยคุณมีวิธีการเปิดไฟล์คุณส่งสตริงไปแล้วจากนั้นก็ทำการตรวจสอบความถูกต้องทุกชนิดก่อนที่จะเข้าสู่ระบบปฏิบัติการ โทรถ้าคุณจัดการที่จะทำสิ่งที่กลายพันธุ์ได้อย่างมีประสิทธิภาพสตริงหลังจากการตรวจสอบความปลอดภัยและก่อนการโทร OS แล้วบูมคุณอยู่ใน ... "
Anurag

60

นี่เป็นบทความที่ดีที่ให้เหตุผลสองประการที่กล่าวถึงแล้วในคำตอบข้างต้น:

  1. ความปลอดภัย : ระบบสามารถแจกบิตที่ละเอียดอ่อนของข้อมูลแบบอ่านอย่างเดียวโดยไม่ต้องกังวลว่าจะมีการเปลี่ยนแปลง
  2. ประสิทธิภาพการทำงาน : ข้อมูลที่ไม่เปลี่ยนรูปนั้นมีประโยชน์มากในการทำสิ่งต่าง ๆ ให้ปลอดภัยต่อเธรด

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


การขยายสตริงจะเล่นความเสียหายด้วยเท่ากับและฝึกงาน JavaDoc พูดว่าเท่ากับ:

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

การสันนิษฐานว่าjava.lang.Stringยังไม่ถึงขั้นสุดท้าย a SafeStringอาจเท่ากับStringและในทางกลับกัน เพราะพวกเขาต้องการแสดงลำดับของอักขระที่เหมือนกัน

จะเกิดอะไรขึ้นถ้าคุณใช้internกับ a SafeString- การSafeStringเข้าไปในสตริงพูลของ JVM หรือไม่ ClassLoaderและทุกวัตถุSafeStringอ้างอิงที่จัดขึ้นเพื่อจากนั้นก็จะได้รับการถูกขังอยู่ในสถานที่สำหรับอายุการใช้งานของ JVM คุณจะได้รับเงื่อนไขการแข่งขันว่าใครจะเป็นคนแรกที่จะเรียงลำดับของตัวละคร - บางทีคุณอาจSafeStringจะชนะอาจจะStringหรือSafeStringโหลดโดย classloader ที่แตกต่างกัน

หากคุณชนะการแข่งขันในสระว่ายน้ำนี่จะเป็นซิงเกิลที่แท้จริงและผู้คนสามารถเข้าถึงสภาพแวดล้อมทั้งหมดของคุณผ่านทางภาพสะท้อนและ secretKey.intern().getClass().getClassLoader()ผ่านการสะท้อนและการ

หรือ JVM สามารถบล็อกหลุมนี้ได้โดยตรวจสอบให้แน่ใจว่ามีการเพิ่มเฉพาะวัตถุ String String (และไม่มีคลาสย่อย) ในพูล

หากมีการใช้งานเท่ากับนั้น SafeString !! = Stringแล้วSafeString.intern! = String.internและSafeStringจะต้องเพิ่มลงในพูล สระว่ายน้ำก็จะกลายเป็นสระว่ายน้ำ<Class, String>แทน<String>และสิ่งที่คุณต้องใช้ในการเข้าร่วมสระว่ายน้ำจะเป็น classloader ที่สดใหม่


2
แน่นอนว่าเหตุผลด้านประสิทธิภาพเป็นเรื่องที่เข้าใจผิด: String เป็นอินเทอร์เฟซที่ฉันสามารถใช้งานได้อย่างมีประสิทธิภาพในแอปพลิเคชันของฉัน
Stephan Eggermont

28

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

หาก String ไม่สามารถเปลี่ยนแปลงได้หรือไม่สุดท้ายคำขอโหลด "java.io.Writer" อาจถูกเปลี่ยนเป็นการโหลด "mil.vogoon.DiskErasingWriter"

การอ้างอิง: ทำไม String จึงไม่เปลี่ยนรูปใน Java


15

String เป็นคลาสแกนกลางมากใน Java หลายสิ่งขึ้นอยู่กับการทำงานในลักษณะที่แน่นอนเช่นการไม่เปลี่ยนรูป

การทำให้คลาสfinalป้องกันคลาสย่อยที่อาจทำลายสมมติฐานเหล่านี้

โปรดทราบว่าแม้ตอนนี้หากคุณใช้การสะท้อนคุณสามารถทำลายสตริง (เปลี่ยนค่าหรือแฮชโค้ด) ได้ การสะท้อนกลับสามารถหยุดได้ด้วยผู้จัดการความปลอดภัย หากStringไม่ใช่finalทุกคนสามารถทำได้

คลาสอื่น ๆ ที่ไม่ได้ประกาศจะfinalอนุญาตให้คุณกำหนดคลาสย่อยที่ค่อนข้างชำรุด ( Listตัวอย่างเช่นคุณอาจมีคลาสที่เพิ่มไปยังตำแหน่งที่ไม่ถูกต้อง) แต่อย่างน้อย JVM ไม่ได้ขึ้นอยู่กับคลาสเหล่านั้นสำหรับการดำเนินการหลัก


6
finalในชั้นเรียนไม่รับประกันการเปลี่ยนไม่ได้ มันรับประกันได้ว่าค่าคงที่ของคลาส (หนึ่งในนั้นไม่สามารถเปลี่ยนแปลงได้) ไม่สามารถเปลี่ยนแปลงได้โดยคลาสย่อย
Kevin Brock

1
@ เควิน: ใช่ รอบชิงชนะเลิศในชั้นเรียนรับประกันได้ว่าไม่มีคลาสย่อย ไม่มีส่วนเกี่ยวข้องกับการเปลี่ยนแปลงไม่ได้
Thilo

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

บางครั้งฉันอ่านคำตอบนี้และฉันคิดว่ามันเป็นคำตอบที่ดีแล้วฉันอ่าน hashcode & เท่ากับจาก 'The Effective Java' และรู้ว่านั่นเป็นคำตอบที่ดีมาก ทุกคนต้องการคำอธิบายฉันแนะนำ ieam 8 & iteam 9 ของหนังสือเล่มเดียวกัน
Abhishek Singh เมื่อ

6

บรูโน่กล่าวว่ามันเกี่ยวกับการเปลี่ยนแปลง มันไม่เพียง แต่เกี่ยวกับ Strings แต่ยังรวมถึง wrappers ใด ๆ เช่น Double, Integer, Character เป็นต้นมีเหตุผลหลายประการดังนี้:

  • ความปลอดภัยด้าย
  • ความปลอดภัย
  • ฮีปที่จัดการโดย Java เอง (แตกต่างจากฮีปทั่วไปที่รวบรวมขยะในลักษณะที่แตกต่างกัน)
  • การจัดการหน่วยความจำ

โดยพื้นฐานแล้วคุณในฐานะโปรแกรมเมอร์สามารถมั่นใจได้ว่าสตริงของคุณจะไม่มีการเปลี่ยนแปลง มันเช่นกันถ้าคุณรู้ว่ามันทำงานอย่างไรสามารถปรับปรุงการจัดการหน่วยความจำ ลองสร้างสตริงที่เหมือนกันสองรายการทีละรายการเช่น "hello" คุณจะสังเกตเห็นว่าถ้าคุณแก้ปัญหาว่าพวกเขามีรหัสเหมือนกันนั่นหมายความว่าพวกเขาเป็นวัตถุเดียวกัน นี่คือความจริงที่ว่า Java ให้คุณทำ สิ่งนี้จะไม่เป็นไปได้ถ้าสตริงนั้นไม่แน่นอน พวกเขาสามารถมีเหมือนกันฉัน ฯลฯ เพราะพวกเขาจะไม่เปลี่ยนแปลง ดังนั้นหากคุณตัดสินใจที่จะสร้างสตริง 1,000,000 คำ "สวัสดี" สิ่งที่คุณต้องทำจริงๆคือสร้างตัวชี้ 1,000,000 ตัวเป็น "สวัสดี" เช่นเดียวกับการกำหนดฟังก์ชั่นใด ๆ ในสตริงหรือ wrappers ใด ๆ ด้วยเหตุผลนั้นจะส่งผลในการสร้างวัตถุอื่น (ดูที่ ID วัตถุอีกครั้ง - มันจะเปลี่ยน)

Aditionally สุดท้ายใน Java ไม่จำเป็นต้องหมายถึงวัตถุที่ไม่สามารถเปลี่ยน (มันจะแตกต่างกันไปเช่น C ++) หมายความว่าที่อยู่ซึ่งชี้ไปไม่สามารถเปลี่ยนแปลงได้ แต่คุณยังสามารถเปลี่ยนคุณสมบัติและ / หรือแอตทริบิวต์ได้ ดังนั้นการเข้าใจความแตกต่างระหว่างความไม่สามารถเปลี่ยนแปลงได้และขั้นสุดท้ายในบางกรณีอาจมีความสำคัญจริงๆ

HTH

อ้างอิง:


1
ฉันไม่เชื่อว่า Strings ไปที่ฮีปอื่นหรือใช้การจัดการหน่วยความจำอื่น พวกเขาแน่นอนเก็บขยะได้
Thilo

2
นอกจากนี้คำหลักสุดท้ายในชั้นเรียนนั้นแตกต่างจากคำหลักสุดท้ายของเขตข้อมูลอย่างสมบูรณ์
Thilo

1
โอเคกับ JVM ของซันสตริงที่ฝึกงาน () ed อาจเข้าสู่การดัดแปรซึ่งไม่ได้เป็นส่วนหนึ่งของกอง แต่นั่นไม่ได้เกิดขึ้นกับ Strings ทั้งหมดหรือ JVM ทั้งหมดอย่างแน่นอน
Thilo

2
ไม่ใช่ Strings ทั้งหมดที่ไปยังพื้นที่นั้นเพียงสตริงที่มีการฝึกงาน Interning นั้นเป็นไปโดยอัตโนมัติสำหรับสตริงตัวอักษร (@Thilo พิมพ์ตามที่คุณส่งความคิดเห็น)
Kevin Brock

ขอบคุณสำหรับคำตอบนี้มีประโยชน์มาก ตอนนี้เรามีข้อเท็จจริงสองข้อแล้ว สตริงเป็นคลาสสุดท้ายและไม่เปลี่ยนรูปเนื่องจากไม่สามารถเปลี่ยนแปลงได้ แต่สามารถอ้างอิงไปยังวัตถุอื่นได้ แต่สิ่งที่เกี่ยวกับ: - String a = new String ("test1"); จากนั้น s = "test2"; ถ้า String เป็นอ็อบเจกต์ระดับสุดท้ายแล้วจะสามารถแก้ไขได้อย่างไร? ฉันจะใช้วัตถุสุดท้ายที่ปรับเปลี่ยนแล้วได้อย่างไร โปรดให้ฉันถ้าฉันถามอะไรผิด
Suresh Sharma

2

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


3
+1 สำหรับ "การออกแบบสำหรับการสืบทอดเป็นเรื่องยาก" BTW นั้นได้รับการอธิบายอย่างดีใน "Effective Java" ของ Bloch
sleske

2

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

กล่าวโดยย่อว่า String ไม่สามารถเปลี่ยนแปลงได้ไม่มีใครสามารถเปลี่ยนเนื้อหาของมันได้เมื่อสร้างขึ้นซึ่งรับประกันว่า hashCode ของ String จะเหมือนกันกับการเรียกใช้หลายครั้ง

ถ้าคุณเห็น Stringคลาสได้ประกาศเป็น

/** Cache the hash code for the string */
private int hash; // Default to 0

และ hashcode()ฟังก์ชั่นมีดังนี้ -

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

หากเป็นคอมพิวเตอร์อยู่แล้วเพียงแค่คืนค่า


2

เพื่อให้แน่ใจว่าเราจะไม่ใช้งานได้ดีขึ้น แน่นอนมันควรจะเป็นอินเทอร์เฟซ

[แก้ไข] อ่าลงคะแนนมากกว่า clueless คำตอบนั้นจริงจังมาก ฉันต้องเขียนโปรแกรมวิธีของฉันเกี่ยวกับการใช้งาน String ที่โง่หลายครั้งนำไปสู่การสูญเสียประสิทธิภาพและประสิทธิภาพที่รุนแรง


2

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


2

นอกเหนือจากเหตุผลที่กล่าวไว้ในคำตอบอื่น ๆ (ความปลอดภัยความไม่สามารถเปลี่ยนแปลงได้) ควรสังเกตว่าStringมีการสนับสนุนภาษาพิเศษ คุณสามารถเขียนStringตัวอักษรและมีการสนับสนุนสำหรับ+ผู้ประกอบการ การอนุญาตให้โปรแกรมเมอร์เขียน subclass Stringจะสนับสนุนการแฮ็กเช่น:

class MyComplex extends String { ... }

MyComplex a = new MyComplex("5+3i");
MyComplex b = new MyComplex("7+4i");
MyComplex c = new MyComplex(a + b);   // would work since a and b are strings,
                                      // and a string + a string is a string.

1

ดีฉันมีความคิดที่แตกต่างกันฉันไม่แน่ใจว่าฉันถูกต้องหรือไม่ แต่ใน Java String เป็นวัตถุเดียวที่สามารถถือว่าเป็นชนิดข้อมูลดั้งเดิมได้เช่นกันฉันหมายความว่าเราสามารถสร้างวัตถุStringเป็นString name = "java " . ตอนนี้เหมือนประเภทข้อมูลดั้งเดิมอื่น ๆ ซึ่งเป็นสำเนาโดยค่าไม่คัดลอกโดยอ้างอิง String คาดว่าจะมีพฤติกรรมเดียวกันดังนั้นจึงเป็นเหตุผลว่าทำไมสตริงจึงเป็นครั้งสุดท้าย นั่นคือสิ่งที่ฉันคิดว่ามัน กรุณาเพิกเฉยหากมันไม่สมเหตุผล


1
ในความคิดของฉันสตริงไม่เคยทำงานเหมือนชนิดดั้งเดิม สตริงตัวอักษรเช่น "java" เป็นวัตถุของคลาส String จริง ๆ (คุณสามารถใช้ตัวดำเนินการ dot ได้ทันทีตามด้วยเครื่องหมายอัญประกาศปิด) ดังนั้นการกำหนดตัวอักษรให้กับตัวแปรสตริงเพียงแค่กำหนดการอ้างอิงวัตถุตามปกติ สิ่งที่แตกต่างคือคลาส String มีการสนับสนุนระดับภาษาที่สร้างไว้ในคอมไพเลอร์ ... เปลี่ยนสิ่งต่าง ๆ ด้วยเครื่องหมายคำพูดคู่เป็นวัตถุสตริงและตัวดำเนินการ + ตามที่กล่าวไว้ข้างต้น
จอร์จี้

1

วาระสุดท้ายของสายอักขระยังปกป้องพวกเขาเป็นมาตรฐาน ใน C ++ คุณสามารถสร้างคลาสย่อยของสตริงได้ดังนั้นร้านค้าการเขียนโปรแกรมทุกคนจึงสามารถมีสตริงรุ่นของตัวเองได้ สิ่งนี้จะนำไปสู่การขาดมาตรฐานที่แข็งแกร่ง


1

สมมติว่าคุณมีชั้นเรียนที่มีวิธีการEmployee greetเมื่อวิธีการที่เรียกว่ามันก็พิมพ์greet Hello everyone!นั่นคือพฤติกรรมที่คาดหวังของgreetวิธีการ

public class Employee {

    void greet() {
        System.out.println("Hello everyone!");
    }
}

ตอนนี้ให้GrumpyEmployeesubclass Employeeและgreetวิธีการแทนที่ดังแสดงด้านล่าง

public class GrumpyEmployee extends Employee {

    @Override
    void greet() {
        System.out.println("Get lost!");
    }
}

ตอนนี้ในรหัสด้านล่างได้ดูsayHelloวิธีการ มันต้องใช้เวลาEmployeeเช่นเป็นพารามิเตอร์และเรียกวิธีการทักทายหวังว่ามันจะพูดแต่สิ่งที่เราได้รับคือHello everyone! Get lost!การเปลี่ยนแปลงพฤติกรรมนี้เป็นเพราะEmployee grumpyEmployee = new GrumpyEmployee();

public class TestFinal {
    static Employee grumpyEmployee = new GrumpyEmployee();

    public static void main(String[] args) {
        TestFinal testFinal = new TestFinal();
        testFinal.sayHello(grumpyEmployee);
    }

    private void sayHello(Employee employee) {
        employee.greet(); //Here you would expect a warm greeting, but what you get is "Get lost!"
    }
}

สถานการณ์นี้สามารถหลีกเลี่ยงได้ถ้าระดับที่ถูกสร้างขึ้นEmployee finalตอนนี้มันก็ขึ้นอยู่กับจินตนาการของคุณจำนวนของความสับสนวุ่นวายโปรแกรมเมอร์หน้าด้านอาจก่อให้เกิดถ้าชั้นไม่ได้ถูกประกาศให้เป็นStringfinal


0

JVM รู้ว่าอะไรไม่เปลี่ยนแปลงหรือไม่? Answer is No, สระว่ายน้ำคงที่ประกอบด้วยเขตข้อมูลที่เปลี่ยนไม่ได้ทั้งหมด แต่เขตข้อมูล / วัตถุที่ไม่เปลี่ยนรูปทั้งหมดจะไม่ถูกเก็บไว้ในกลุ่มคงที่เท่านั้น มีเพียงเราเท่านั้นที่นำไปใช้งานในลักษณะที่ทำให้เกิดความไม่มั่นคงและคุณสมบัติของมัน CustomString สามารถนำมาใช้ได้โดยไม่ทำให้สุดท้ายใช้ MarkerInterface ซึ่งจะให้พฤติกรรมพิเศษของจาวาสำหรับการรวมกำไรของมันคุณลักษณะยังคงรออยู่!


0

คำตอบส่วนใหญ่เกี่ยวข้องกับความไม่เปลี่ยนแปลง - เหตุใดจึงไม่สามารถอัปเดตวัตถุประเภท String มีการพูดคุยที่ดีมากมายที่นี่และชุมชน Java น่าจะยอมรับการเปลี่ยนแปลงไม่ได้ในฐานะอาจารย์ใหญ่ (ไม่กลั้นลมหายใจของฉัน)

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

newtype AccountCode = AccountCode Text
newtype FundCode = FundCode Text

ดังนั้นฉันจะนำข้อเสนอแนะต่อไปนี้ไปข้างหน้าเป็นการปรับปรุงภาษาจาวา:

newtype AccountCode of String;
newtype FundCode of String;

AccountCode acctCode = "099876";
FundCode fundCode = "099876";

acctCode.equals(fundCode);  // evaluates to false;
acctCode.toString().equals(fundCode.toString());  // evaluates to true;

acctCode=fundCode;  // compile error
getAccount(fundCode);  // compile error

(หรือบางทีเราอาจจะเริ่มตัดทอนตัวเองออกจาก Java)


-1

หากคุณสร้างสตริงหนึ่งครั้งมันจะพิจารณาว่าเป็นวัตถุถ้าคุณต้องการแก้ไขมันเป็นไปไม่ได้มันจะสร้างวัตถุใหม่


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