พื้นหลัง
มีสามที่สุดท้ายที่สามารถแสดงใน Java:
การทำให้คลาสสุดท้ายป้องกันคลาสย่อยทั้งหมดของคลาส ทำให้วิธีสุดท้ายป้องกันคลาสย่อยของวิธีการเอาชนะมัน การทำให้ฟิลด์สุดท้ายป้องกันไม่ให้มีการเปลี่ยนแปลงในภายหลัง
ความเข้าใจผิด
มีการเพิ่มประสิทธิภาพที่เกิดขึ้นรอบ ๆ วิธีการและเขตข้อมูลสุดท้าย
วิธีสุดท้ายทำให้ HotSpot ง่ายขึ้นในการปรับให้เหมาะสมผ่านทางอินไลน์ อย่างไรก็ตาม HotSpot ทำเช่นนี้แม้ว่าวิธีการจะไม่เป็นผลสุดท้ายเนื่องจากสามารถใช้งานได้บนสมมติฐานที่ว่ามันไม่ได้ถูกเขียนทับจนกว่าจะพิสูจน์ได้ เพิ่มเติมเกี่ยวกับเรื่องนี้ดังนั้น
ตัวแปรสุดท้ายสามารถเพิ่มประสิทธิภาพในเชิงรุกและเพิ่มเติมเกี่ยวกับการที่สามารถอ่านได้ในส่วน JLS 17.5.3
แต่ด้วยความเข้าใจอย่างใดอย่างหนึ่งควรจะตระหนักว่าค่าการเพิ่มประสิทธิภาพเหล่านี้จะเกี่ยวกับการทำชั้นสุดท้าย ไม่มีการเพิ่มประสิทธิภาพโดยการทำให้ชั้นเรียนสุดท้าย
ด้านสุดท้ายของชั้นเรียนไม่เกี่ยวข้องกับสิ่งที่ไม่สามารถเปลี่ยนแปลงได้เช่นกัน หนึ่งสามารถมีคลาสที่ไม่เปลี่ยนรูป (เช่นBigInteger ) ที่ไม่เป็นที่สิ้นสุดหรือคลาสที่ไม่แน่นอนและสุดท้าย (เช่นStringBuilder ) การตัดสินใจว่าคลาสใดควรเป็นที่สุดเป็นคำถามของการออกแบบ
การออกแบบขั้นสุดท้าย
สตริงเป็นหนึ่งในประเภทข้อมูลที่ใช้มากที่สุด พวกเขาพบว่าเป็นกุญแจสำคัญในแผนที่พวกเขาเก็บชื่อผู้ใช้และรหัสผ่านพวกเขาเป็นสิ่งที่คุณอ่านจากแป้นพิมพ์หรือเขตข้อมูลบนหน้าเว็บ สตริงทุกที่
แผนที่
สิ่งแรกที่ต้องพิจารณาว่าจะเกิดอะไรขึ้นถ้าคุณสามารถซับคลาสสตริงได้ตระหนักว่ามีใครบางคนสามารถสร้างคลาสสตริงที่ไม่แน่นอนซึ่งจะดูเหมือนเป็นสตริง สิ่งนี้จะทำให้แผนที่สับสนได้ทุกที่
พิจารณารหัสสมมุตินี้:
Map t = new TreeMap<String, Integer>();
Map h = new HashMap<String, Integer>();
MyString one = new MyString("one");
MyString two = new MyString("two");
t.put(one, 1); h.put(one, 1);
t.put(two, 2); h.put(two, 2);
one.prepend("z");
นี่เป็นปัญหาของการใช้คีย์ที่ไม่แน่นอนโดยทั่วไปกับแผนที่ แต่สิ่งที่ฉันพยายามจะไปถึงก็คือมีหลายสิ่งที่เกี่ยวกับตัวแบ่งแผนที่ รายการไม่อยู่ในจุดที่ถูกต้องในแผนที่อีกต่อไป ใน HashMap ค่าแฮชมีการเปลี่ยนแปลง (ควรมี) และทำให้ไม่อยู่ในรายการที่ถูกต้องอีกต่อไป ใน TreeMap ตอนนี้ต้นไม้จะแตกเพราะหนึ่งในโหนดนั้นอยู่ผิดด้าน
เนื่องจากการใช้สตริงสำหรับคีย์เหล่านี้เป็นเรื่องปกติดังนั้นพฤติกรรมนี้ควรได้รับการป้องกันโดยทำให้สตริงเป็นที่สิ้นสุด
คุณอาจสนใจอ่านทำไม String ถึงไม่เปลี่ยนแปลงใน Java? สำหรับข้อมูลเพิ่มเติมเกี่ยวกับลักษณะที่ไม่เปลี่ยนแปลงของ Strings
สตริงชั่วร้าย
มีตัวเลือกที่ชั่วร้ายมากมายสำหรับ Strings ลองพิจารณาว่าฉันสร้างสตริงที่มักจะคืนค่าจริงเมื่อมีการเรียก ... และส่งผ่านการตรวจสอบรหัสผ่านหรือไม่ หรือทำเพื่อที่การมอบหมายให้ MyString จะส่งสำเนาของ String ไปยังที่อยู่อีเมลบางอัน?
สิ่งเหล่านี้เป็นไปได้จริงมากเมื่อคุณมีความสามารถในการซับสตริงคลาส
การเพิ่มประสิทธิภาพสตริง Java.lang
ในขณะที่ก่อนหน้านี้ฉันพูดถึงว่าขั้นตอนสุดท้ายจะไม่ทำให้ String เร็วขึ้น อย่างไรก็ตามคลาส String (และคลาสอื่น ๆ ในjava.lang
) ใช้การป้องกันระดับแพ็กเกจของฟิลด์และวิธีการเพื่ออนุญาตให้java.lang
คลาสอื่น ๆสามารถใช้งาน tinker กับ internals แทนการผ่าน API สาธารณะสำหรับ String ตลอดเวลา ฟังก์ชั่นเช่นgetCharsโดยไม่มีการตรวจสอบช่วงหรือlastIndexOfที่ใช้โดย StringBuffer หรือตัวสร้างที่แชร์อาเรย์พื้นฐาน (โปรดทราบว่าเป็นสิ่ง Java 6 ที่มีการเปลี่ยนแปลงเนื่องจากปัญหาหน่วยความจำ)
หากมีคนสร้างคลาสย่อยของ String มันจะไม่สามารถแบ่งปันการปรับปรุงเหล่านั้นได้ (เว้นแต่จะเป็นส่วนหนึ่งของjava.lang
ด้วย แต่เป็นแพ็คเกจที่ปิดผนึก )
มันยากที่จะออกแบบบางสิ่งเพื่อขยาย
การออกแบบสิ่งที่จะขยายเป็นเรื่องยาก หมายความว่าคุณต้องเปิดเผยบางส่วนของ internals ของคุณเพื่อให้สามารถแก้ไขได้
สตริงที่ขยายได้อาจไม่มีการแก้ไขหน่วยความจำรั่ว ส่วนเหล่านั้นจะต้องได้รับการสัมผัสกับคลาสย่อยและการเปลี่ยนรหัสนั้นจะหมายถึงคลาสย่อยจะแตก
Java ภูมิใจในความเข้ากันได้แบบย้อนหลังและโดยการเปิดคลาสหลักเพื่อขยายส่วนหนึ่งสูญเสียความสามารถบางอย่างในการแก้ไขสิ่งต่างๆในขณะที่ยังคงความสามารถในการคำนวณด้วยคลาสย่อยของบุคคลที่สาม
Checkstyleมีกฎที่บังคับใช้ (ซึ่งทำให้ฉันหงุดหงิดจริงๆเมื่อเขียนโค้ดภายใน) เรียกว่า "DesignForExtension" ซึ่งบังคับให้ทุกคลาสเป็น:
- บทคัดย่อ
- สุดท้าย
- การใช้งานที่ว่างเปล่า
เหตุผลที่:
สไตล์การออกแบบ API นี้ช่วยปกป้องซูเปอร์คลาสจากการถูกทำลายโดยคลาสย่อย ข้อเสียคือคลาสย่อยถูก จำกัด ในความยืดหยุ่นโดยเฉพาะอย่างยิ่งพวกเขาไม่สามารถป้องกันการเรียกใช้โค้ดในซูเปอร์คลาส แต่นั่นหมายความว่าคลาสย่อยไม่สามารถทำให้สถานะของซูเปอร์คลาสนั้นเสียหายได้โดยลืมเรียกวิธีซูเปอร์
การอนุญาตให้ขยายคลาสการใช้งานหมายความว่าคลาสย่อยอาจทำให้สถานะของคลาสนั้นเสียหายและทำให้คลาสนั้นรับประกันได้หลายอย่างที่ซุปเปอร์คลาสให้นั้นไม่ถูกต้อง สำหรับสิ่งที่ซับซ้อนเช่นเดียวกับ String มันเกือบจะแน่นอนว่าการเปลี่ยนส่วนของมันจะทำลายบางสิ่งบางอย่าง
นักพัฒนา hurbis
ส่วนหนึ่งของการเป็นนักพัฒนา พิจารณาความเป็นไปได้ที่นักพัฒนาแต่ละคนจะสร้าง subclass สตริงของตัวเองกับคอลเลกชันของตัวเองutilsในนั้น แต่ตอนนี้คลาสย่อยเหล่านี้ไม่สามารถมอบหมายให้กันและกันได้อย่างอิสระ
WleaoString foo = new WleaoString("foo");
MichaelTString bar = foo; // This doesn't work.
วิธีนี้นำไปสู่ความบ้าคลั่ง กำลังส่งไปยัง String ทั่วทุกสถานที่และตรวจสอบเพื่อดูว่า String เป็นอินสแตนซ์ของคลาส String ของคุณหรือไม่หากไม่สร้างสตริงใหม่ขึ้นอยู่กับสตริงนั้นและ ... เพียงแค่ไม่ใช่ อย่า
ฉันแน่ใจว่าคุณสามารถเขียน string คลาสดี ... แต่ปล่อยให้การเขียนการใช้งานหลายสตริงกับคนบ้าผู้ที่เขียน C ++ และมีการจัดการกับstd::string
และchar*
และอะไรบางอย่างจากการเพิ่มและSStringและส่วนที่เหลือทั้งหมด
จาวาสตริงเวทมนตร์
มีสิ่งมหัศจรรย์หลายอย่างที่ Java ทำกับ Strings สิ่งเหล่านี้ทำให้โปรแกรมเมอร์จัดการได้ง่ายขึ้น แต่แนะนำความไม่สอดคล้องของภาษา การอนุญาตให้คลาสย่อยใน String ใช้ความคิดที่สำคัญมากเกี่ยวกับวิธีจัดการกับสิ่งมหัศจรรย์เหล่านี้:
สตริงตัวอักษร (JLS 3.10.5 )
มีรหัสที่อนุญาตให้ทำ:
String foo = "foo";
นี่ไม่ควรสับสนกับชกมวยประเภทตัวเลขเช่นจำนวนเต็ม คุณไม่สามารถทำแต่คุณสามารถทำได้1.toString()
"foo".concat(bar)
+
ประกอบการ (JLS 15.18.1 )
ไม่มีประเภทการอ้างอิงอื่นใน Java ที่อนุญาตให้ผู้ปฏิบัติงานใช้งาน เชือกเป็นพิเศษ ตัวดำเนินการเชื่อมต่อสตริงยังทำงานที่ระดับคอมไพเลอร์เพื่อที่"foo" + "bar"
จะกลายเป็น"foobar"
เมื่อมันถูกรวบรวมมากกว่าที่รันไทม์
การแปลงสตริง (JLS 5.1.11 )
วัตถุทั้งหมดสามารถแปลงเป็นสตริงได้โดยใช้พวกมันในบริบทของสตริง
การใช้สตริง ( JavaDoc )
คลาส String มีการเข้าถึงพูลของสตริงที่อนุญาตให้มีการรับรองแบบบัญญัติของวัตถุซึ่งถูกเติมด้วยชนิดคอมไพล์ด้วยตัวอักษรสตริง
การอนุญาตให้คลาสย่อยของ String นั้นหมายความว่าบิตเหล่านี้กับสตริงที่ทำให้โปรแกรมง่ายขึ้นจะกลายเป็นเรื่องยากมากหรือเป็นไปไม่ได้ที่จะทำเมื่อเป็นไปได้ที่ชนิดของสตริงอื่น