1. บทนำสู่หมวดหมู่ที่ไม่เปลี่ยนรูป
คลาสที่ไม่เปลี่ยนรูป: คลาสที่เรียกว่าไม่เปลี่ยนรูปหมายความว่าเมื่ออินสแตนซ์ของคลาสนี้ถูกสร้างขึ้นค่าตัวแปรสมาชิกจะไม่สามารถเปลี่ยนแปลงได้ ตัวอย่างเช่นคลาสที่ไม่เปลี่ยนรูปจำนวนมากที่มาพร้อมกับ JDK: Interger, Long และ String ฯลฯ
คลาสตัวแปร: เปรียบเทียบกับคลาสที่ไม่เปลี่ยนรูปคลาสที่ไม่แน่นอนสามารถเปลี่ยนค่าตัวแปรสมาชิกหลังจากสร้างอินสแตนซ์ คลาสส่วนใหญ่ที่สร้างขึ้นในการพัฒนาเป็นของคลาสที่ไม่แน่นอน
2. ข้อดีของชั้นเรียนที่ไม่เปลี่ยนรูป
หลังจากพูดคุยเกี่ยวกับความแตกต่างระหว่างคลาสที่ไม่แน่นอนและชั้นเรียนที่ไม่เปลี่ยนรูปเราต้องเข้าใจเพิ่มเติมว่าทำไมจึงมีชั้นเรียนที่ไม่เปลี่ยนรูป คุณลักษณะดังกล่าวมีประโยชน์อะไรบ้างที่นำมาสู่ Java?
1. ความปลอดภัยของด้าย
วัตถุที่ไม่เปลี่ยนรูปเป็นเธรดที่ปลอดภัยและสามารถใช้ร่วมกันระหว่างเธรด ไม่จำเป็นต้องใช้กลไกพิเศษเพื่อให้แน่ใจว่าปัญหาการซิงโครไนซ์เนื่องจากค่าของวัตถุไม่สามารถเปลี่ยนแปลงได้ มันสามารถลดความเป็นไปได้ของข้อผิดพลาดที่เกิดขึ้นพร้อมกันเนื่องจากไม่จำเป็นต้องใช้กลไกการล็อคบางอย่างเพื่อให้แน่ใจว่าปัญหาความสอดคล้องของหน่วยความจำซึ่งจะช่วยลดค่าใช้จ่ายในการซิงโครไนซ์
2. ง่ายต่อการสร้างใช้และทดสอบ
3 ....
วิธีการออกแบบคลาสที่ไม่เปลี่ยนรูป
สำหรับการออกแบบชั้นเรียนที่ไม่เปลี่ยนรูปฉันสรุปหลักการต่อไปนี้เป็นการส่วนตัว:
1. เพิ่มตัวดัดแปลงสุดท้ายในคลาสเพื่อให้แน่ใจว่าคลาสไม่ได้รับการสืบทอด
หากคลาสสามารถสืบทอดได้มันจะทำลายกลไกการเปลี่ยนแปลงของชั้นเรียนตราบใดที่คลาสการสืบทอดจะแทนที่วิธีการของคลาสแม่และคลาสการสืบทอดสามารถเปลี่ยนค่าตัวแปรสมาชิกแล้วเมื่อคลาสเด็กปรากฏเป็นคลาสแม่ก็ไม่สามารถรับประกันได้ว่าคลาสปัจจุบันจะกลายพันธุ์ได้หรือไม่
2. ตรวจสอบให้แน่ใจว่ามีการเพิ่มตัวแปรสมาชิกทั้งหมดเป็นส่วนตัวและมีการปรับเปลี่ยนขั้นสุดท้าย
วิธีนี้ทำให้มั่นใจได้ว่าตัวแปรสมาชิกไม่สามารถเปลี่ยนแปลงได้ แต่มันก็ไม่เพียงพอที่จะทำเช่นนี้เพราะถ้าเป็นตัวแปรสมาชิกวัตถุก็เป็นไปได้ที่จะเปลี่ยนค่าจากภายนอก ดังนั้นจุดที่สี่จึงเกิดขึ้นสำหรับข้อบกพร่องนี้
3. ไม่มีวิธีการที่จะเปลี่ยนตัวแปรสมาชิกรวมถึงตัวตั้งค่า
หลีกเลี่ยงการเปลี่ยนค่าของตัวแปรสมาชิกผ่านอินเทอร์เฟซอื่น ๆ และทำลายคุณสมบัติที่ไม่เปลี่ยนรูป
4. เริ่มต้นสมาชิกทั้งหมดผ่านตัวสร้างและดำเนินการสำเนาลึก (สำเนาลึก)
หากวัตถุที่ส่งผ่านโดยตัวสร้างจะถูกกำหนดโดยตรงไปยังตัวแปรสมาชิกมันยังคงสามารถเปลี่ยนแปลงได้โดยการปรับเปลี่ยนวัตถุที่เข้ามาซึ่งจะทำให้ค่าของตัวแปรภายในเปลี่ยน ตัวอย่างเช่น:
ระดับสุดท้ายของระดับสาธารณะ Immutabledemo {Private Final Int [] MyArray; สาธารณะ immutabledemo (int [] array) {this.myarray = array; // ผิด } }วิธีนี้ไม่สามารถรับประกันความไม่สามารถเปลี่ยนแปลงได้ MyArray และ Array ชี้ไปที่ที่อยู่หน่วยความจำเดียวกัน ผู้ใช้สามารถเปลี่ยนค่าภายใน MyArray โดยการปรับเปลี่ยนค่าของวัตถุอาร์เรย์ที่อยู่นอก Immutabledemo
เพื่อให้แน่ใจว่าค่าภายในไม่ได้รับการแก้ไขสามารถใช้สำเนาความลึกเพื่อสร้างหน่วยความจำใหม่เพื่อบันทึกค่าที่เข้ามา วิธีที่ถูกต้องในการทำ:
ระดับสุดท้ายของคลาสสาธารณะ Myimmutabledemo {Private Final Int [] MyArray; สาธารณะ myimmutabledemo (int [] array) {this.myarray = array.clone (); -5. ในวิธีการ getter อย่าส่งคืนวัตถุโดยตรง แต่โคลนวัตถุและส่งคืนสำเนาของวัตถุ
วิธีการนี้ยังป้องกันการรั่วไหลของวัตถุและป้องกันการทำงานโดยตรงของตัวแปรสมาชิกหลังจากได้รับวัตถุสมาชิกที่ไม่แน่นอนภายในผ่าน getters ส่งผลให้เกิดการเปลี่ยนแปลงในตัวแปรสมาชิก
iv. ความไม่เปลี่ยนรูปของวัตถุสตริง
วัตถุสตริงไม่สามารถเปลี่ยนแปลงได้หลังจากการสร้างหน่วยความจำ การสร้างวัตถุที่ไม่เปลี่ยนรูปโดยทั่วไปเป็นไปตามหลักการ 5 ข้อข้างต้น ลองมาดูกันว่ารหัสสตริงถูกนำไปใช้อย่างไร
Public Final Class StringImplements java.io.serializable, เปรียบเทียบ <string>, charsequence {/** ค่าที่ใช้สำหรับการจัดเก็บอักขระ */ค่าถ่านสุดท้ายส่วนตัว [];/** ออฟเซ็ตเป็นดัชนีแรกของที่เก็บข้อมูลที่ใช้ */Private Final Int Offset;/** จำนวนคือจำนวนอักขระในสตริง */การนับ int สุดท้ายส่วนตัว;/** แคชรหัสแฮชสำหรับสตริง*/แฮช int ส่วนตัว; // ค่าเริ่มต้นถึง 0..Public String (ค่าถ่าน []) {this.value = array.copyof (value, value.length); // การดำเนินการคัดลอกลึก} ... ถ่านสาธารณะ [] toCharArray () {// ไม่สามารถใช้อาร์เรย์ copyof เนื่องจากปัญหาการเริ่มต้นของชั้นเรียนการสั่งซื้อผลการสั่งซื้อ [] = char ใหม่ [value.length]; system.arraycopy (ค่า, 0, ผลลัพธ์, 0, value.length); ผลตอบแทน;} ... }}}}}ดังที่แสดงในรหัสด้านบนสามารถสังเกตรายละเอียดการออกแบบต่อไปนี้ได้:
1. สตริปคลาสได้รับการแก้ไขโดยรอบชิงชนะเลิศและไม่สามารถสืบทอดได้
2. สมาชิกทั้งหมดของสตริงถูกตั้งค่าเป็นตัวแปรส่วนตัว
3. ไม่มีค่าตัวตั้งค่า
4. และตั้งค่าและชดเชยเป็นขั้นสุดท้าย
5. เมื่อผ่านในค่าอาร์เรย์ตัวแปร [] ให้คัดลอกแทนการคัดลอกค่า [] โดยตรงไปยังตัวแปรภายใน
6. เมื่อได้รับค่ามันจะไม่ส่งคืนการอ้างอิงวัตถุโดยตรง แต่ส่งคืนสำเนาของวัตถุ
สิ่งนี้สอดคล้องกับลักษณะของประเภทค่าคงที่ที่สรุปไว้ข้างต้นและยังทำให้มั่นใจได้ว่าประเภทสตริงเป็นคลาสที่ไม่เปลี่ยนรูป
5. ข้อดีและข้อเสียของการเปลี่ยนแปลงของวัตถุสตริง
จากการวิเคราะห์ส่วนก่อนหน้าข้อมูลสตริงไม่เปลี่ยนรูปดังนั้นประโยชน์ของการตั้งค่าคุณสมบัติดังกล่าวคืออะไร? ฉันสรุปได้ดังนี้:
1. ข้อกำหนดสำหรับพูลคงที่สตริง
พูลคงที่สตริงสามารถใช้ค่าคงที่อักขระบางตัวในสระคงที่หลีกเลี่ยงการสร้างวัตถุเดียวกันใหม่ทุกครั้งและประหยัดพื้นที่เก็บข้อมูล แต่ถ้าสตริงเป็นตัวแปรสตริงของเนื้อหาเดียวกันก็ชี้ไปที่พื้นที่หน่วยความจำเดียวกันของพูลคงที่ เมื่อตัวแปรเปลี่ยนค่าของหน่วยความจำนั้นค่าอื่น ๆ จะเปลี่ยนไป ดังนั้นจึงไม่สอดคล้องกับความตั้งใจดั้งเดิมของการออกแบบสระว่ายน้ำอย่างต่อเนื่อง
2. ข้อควรพิจารณาด้านความปลอดภัยของด้าย
อินสแตนซ์สตริงเดียวกันสามารถแชร์ได้หลายเธรด ด้วยวิธีนี้ไม่จำเป็นต้องใช้การซิงโครไนซ์เนื่องจากปัญหาด้านความปลอดภัยของเธรด สตริงมีความปลอดภัยด้าย
3. ชั้นเรียนชั้นเรียนต้องใช้สตริงและความไม่สามารถเปลี่ยนแปลงได้ให้ความปลอดภัยเพื่อให้คลาสที่ถูกต้องโหลด ตัวอย่างเช่นหากคุณต้องการโหลดคลาส java.sql.connection และค่านี้จะเปลี่ยนเป็น myhacked.connection มันจะทำให้เกิดความเสียหายที่ไม่รู้จักกับฐานข้อมูลของคุณ
4. สนับสนุนการทำแผนที่แฮชและแคช
เนื่องจากสตริงไม่เปลี่ยนรูป hashcode จึงถูกแคชเมื่อมันถูกสร้างขึ้นและไม่จำเป็นต้องคำนวณใหม่ สิ่งนี้ทำให้สตริงนั้นเหมาะสมมากกับปุ่มในแผนที่และความเร็วในการประมวลผลของสตริงนั้นเร็วกว่าวัตถุสำคัญอื่น ๆ นี่คือเหตุผลที่คีย์ใน HashMap มักจะใช้สตริง
ข้อบกพร่อง:
1. หากมีความจำเป็นที่จะต้องเปลี่ยนค่าของวัตถุสตริงจะมีการสร้างวัตถุสตริงจำนวนมาก
6. วัตถุสตริงไม่เปลี่ยนรูปจริงหรือไม่?
แม้ว่าวัตถุสตริงจะตั้งค่าเป็นขั้นสุดท้าย แต่ก็ช่วยให้มั่นใจได้ว่าตัวแปรสมาชิกนั้นไม่สามารถเปลี่ยนแปลงได้ผ่านกลไกต่าง ๆ อย่างไรก็ตามมันยังสามารถเปลี่ยนแปลงได้ผ่านกลไกการสะท้อนกลับ ตัวอย่างเช่น:
// สร้างสตริง "Hello World" และกำหนดให้กับการอ้างอิง sstring s = "Hello World"; System.out.println ("s =" + s); // hello world // รับฟิลด์ค่าในฟิลด์คลาสสตริง Valuefieldofstring = string.class.getDeclaredField ("value"); // เปลี่ยนการอนุญาตการเข้าถึงของแอตทริบิวต์ค่า ValueFieldField.SetAccessible (จริง); '_'; System.out.println ("s =" + s); // hello_worldผลการพิมพ์คือ:
s = hello worlds = hello_world
พบว่าค่าของสตริงมีการเปลี่ยนแปลง กล่าวคือวัตถุที่เรียกว่า "ไม่เปลี่ยนแปลง" สามารถแก้ไขได้ผ่านการสะท้อน
สรุป
คลาสที่ไม่เปลี่ยนรูปเป็นค่าของการเดินทางผ่านสมาชิกที่ไม่สามารถเปลี่ยนแปลงได้หลังจากสร้างอินสแตนซ์ คุณลักษณะนี้ช่วยให้คลาสที่ไม่เปลี่ยนรูปสามารถให้คุณสมบัติที่ปลอดภัยจากเธรด แต่ยังนำค่าใช้จ่ายของการสร้างวัตถุ การเปลี่ยนแปลงแอตทริบิวต์แต่ละครั้งคือการสร้างวัตถุใหม่ใหม่ JDK ยังมีคลาสที่ไม่เปลี่ยนแปลงมากมายเช่นจำนวนเต็ม, คู่, สตริง ฯลฯ ลักษณะที่ไม่เปลี่ยนรูปของสตริงส่วนใหญ่จะตอบสนองความต้องการของการรวมการรวมกันความปลอดภัยของด้ายและการโหลดคลาส การใช้อย่างมีเหตุผลของชั้นเรียนที่ไม่เปลี่ยนรูปสามารถนำประโยชน์มาใช้
ข้างต้นเป็นกลไกที่ไม่เปลี่ยนรูปของ Java (ไม่เปลี่ยนรูป) และความไม่เปลี่ยนรูปของสตริง (แนะนำ) แนะนำให้คุณรู้จักโดยบรรณาธิการ ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับคุณทันเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!