วิธีการเริ่มต้นเพิ่มคุณสมบัติใหม่ที่ดีมากในชุดคำสั่งของ JVM หลังจากใช้วิธีการเริ่มต้นหากมีการเพิ่มวิธีการใหม่ลงในอินเทอร์เฟซในไลบรารีคลาสผู้ใช้ที่ใช้อินเทอร์เฟซนี้สามารถรับการใช้งานเริ่มต้นของวิธีนี้โดยอัตโนมัติ เมื่อผู้ใช้ต้องการอัปเดตคลาสการใช้งานของเขาเพียงแค่แทนที่วิธีเริ่มต้นนี้และแทนที่ด้วยการใช้งานที่มีความหมายมากขึ้นในสถานการณ์ที่เฉพาะเจาะจง สิ่งที่ดียิ่งกว่าคือผู้ใช้สามารถเรียกใช้การใช้งานเริ่มต้นของอินเทอร์เฟซในวิธีการเขียนใหม่เพื่อเพิ่มฟังก์ชั่นพิเศษบางอย่าง
ทุกอย่างค่อนข้างดีจนถึงตอนนี้ อย่างไรก็ตาม การเพิ่มวิธีการเริ่มต้นไปยังอินเตอร์เฟส Java ที่มีอยู่อาจนำไปสู่ความไม่ลงรอยกันของรหัส มันง่ายที่จะเข้าใจโดยดูตัวอย่าง สมมติว่ามีไลบรารีที่ต้องการให้ผู้ใช้ใช้หนึ่งในอินเทอร์เฟซเป็นอินพุต:
อินเตอร์เฟส simpleInput {void foo (); Void Bar ();} คลาสบทคัดย่อ SimpleInputAdapter ใช้ SimpleInput {@Override Public Public Void Bar () {// พฤติกรรมเริ่มต้นบางอย่าง ... }}ก่อน Java 8 การรวมกันของอินเทอร์เฟซด้านบนและคลาสอะแดปเตอร์ที่สอดคล้องกันเป็นรูปแบบที่พบบ่อยมากในภาษา Java นักพัฒนาห้องสมุดชั้นเรียนจัดเตรียมอะแดปเตอร์เพื่อลดจำนวนการเข้ารหัสสำหรับผู้บริโภคในห้องสมุด อย่างไรก็ตามจุดประสงค์ของการจัดหาอินเทอร์เฟซนี้เพื่อให้บรรลุความสัมพันธ์ที่คล้ายคลึงกับการสืบทอดหลายครั้ง
สมมติว่าผู้ใช้ใช้อะแดปเตอร์นี้:
คลาส MyInput ขยาย SimpleInputAdapter {@Override โมฆะสาธารณะ foo () {// ทำอะไรบางอย่าง ... } @Override โมฆะสาธารณะแถบสาธารณะ () {super.bar (); // ทำอะไรเพิ่มเติม ... }}ด้วยการใช้งานนี้ผู้ใช้สามารถโต้ตอบกับห้องสมุด โปรดทราบว่าการใช้งานนี้จะแทนที่วิธี BAR เพื่อเพิ่มฟังก์ชั่นเพิ่มเติมในการใช้งานเริ่มต้น
แล้วจะเกิดอะไรขึ้นถ้าห้องสมุดนี้อพยพไปยัง Java 8? ก่อนอื่นไลบรารีนี้มีแนวโน้มที่จะทิ้งคลาสอะแดปเตอร์และย้ายฟังก์ชั่นนี้ไปยังวิธีเริ่มต้น ในท้ายที่สุดอินเทอร์เฟซนี้จะมีลักษณะเช่นนี้:
อินเตอร์เฟส simpleInput {void foo (); void bar เริ่มต้น () {// พฤติกรรมเริ่มต้น}}}ด้วยอินเทอร์เฟซใหม่นี้ผู้ใช้จะต้องอัปเดตรหัสของเขาเพื่อใช้วิธีเริ่มต้นนี้แทนคลาสอะแดปเตอร์ หนึ่งในประโยชน์ที่ยอดเยี่ยมของการใช้อินเทอร์เฟซใหม่แทนคลาสอะแดปเตอร์คือผู้ใช้สามารถสืบทอดคลาสอื่นแทนคลาสอะแดปเตอร์นี้ เริ่มต้นด้วยการฝึกฝนและแปลงคลาส MyInput ให้เป็นวิธีเริ่มต้น เนื่องจากตอนนี้เราสามารถสืบทอดคลาสอื่น ๆ เราจะพยายามขยายคลาสฐานบุคคลที่สามเพิ่มเติม สิ่งที่คลาสฐานนี้ไม่สำคัญที่นี่ สมมติว่าสิ่งนี้สมเหตุสมผลสำหรับกรณีการใช้งานของเรา
Class MyInput ขยาย ThirdPartyBaseClass ใช้ SimpleInput {@Override โมฆะสาธารณะ foo () {// ทำอะไรบางอย่าง ... } @Override โมฆะบาร์สาธารณะ () {simpleInput.super.foo (); // ทำอะไรเพิ่มเติม ... }}เพื่อให้ได้ฟังก์ชั่นเดียวกับคลาสดั้งเดิมเราใช้ไวยากรณ์ Java 8 ใหม่เพื่อเรียกวิธีเริ่มต้นของอินเทอร์เฟซ ในทำนองเดียวกันเราใส่ตรรกะของ mymethod ลงในคลาสฐาน myBase คุณสามารถผ่อนคลายหลังจากทุบไหล่ มันยอดเยี่ยมหลังจากการปรับโครงสร้างใหม่!
ห้องสมุดที่เราใช้นี้ได้รับการปรับปรุงอย่างมาก อย่างไรก็ตามบุคลากรการบำรุงรักษาจำเป็นต้องเพิ่มอินเทอร์เฟซอื่นเพื่อใช้ฟังก์ชันเพิ่มเติมบางอย่าง อินเทอร์เฟซนี้เรียกว่า CompExInput ซึ่งสืบทอดคลาส SimpleInput และเพิ่มวิธีการเพิ่มเติม เนื่องจากเชื่อกันโดยทั่วไปว่าวิธีการเริ่มต้นสามารถเพิ่มได้ด้วยความมั่นใจเจ้าหน้าที่การบำรุงรักษาจะแทนที่วิธีเริ่มต้นของคลาส SimpleInput และเพิ่มการกระทำพิเศษบางอย่างเพื่อให้ผู้ใช้มีการใช้งานเริ่มต้นที่ดีขึ้น ท้ายที่สุดนี่เป็นเรื่องธรรมดามากเมื่อใช้คลาสอะแดปเตอร์:
Interface ComplexInput ขยาย SimpleInput {void qox (); @Override void bar () {simpleInput.super.bar (); // ซับซ้อนมากเราต้องทำมากกว่านี้ ... }}ฟีเจอร์ใหม่นี้ดูดีมากดังนั้นผู้ดูแลชั้นที่สามของ PartpartyBaseclass จึงตัดสินใจใช้ห้องสมุดนี้ด้วย เพื่อให้บรรลุเป้าหมายนี้เขาได้ใช้คลาสที่สาม Partybaseclass ไปยังอินเตอร์เฟสเชิงซ้อน
แต่สิ่งนี้หมายความว่าสำหรับคลาส MyInput? เนื่องจากมันสืบทอดคลาส ThirdPartyBaseclass อินเตอร์เฟสเชิงซ้อนอินเตอร์เฟสจึงถูกนำมาใช้โดยค่าเริ่มต้น ด้วยวิธีนี้การเรียกใช้วิธีเริ่มต้นของ SimpleInput ไม่ถูกกฎหมาย ผลลัพธ์คือรหัสของผู้ใช้ไม่สามารถรวบรวมได้ในที่สุด นอกจากนี้วิธีนี้เป็นไปไม่ได้อย่างสมบูรณ์ที่จะโทรเพราะ Java พิจารณาวิธีการซูเปอร์ซูเปอร์นี้เพื่อเรียกชั้นเรียนหลักทางอ้อมที่ผิดกฎหมาย คุณสามารถเรียกใช้วิธีเริ่มต้นของอินเตอร์เฟสคอมเพล็กซ์ อย่างไรก็ตามสิ่งแรกนี้ต้องการให้คุณใช้อินเทอร์เฟซนี้อย่างชัดเจนในคลาส MyInput สำหรับผู้ใช้ห้องสมุดนี้การเปลี่ยนแปลงเหล่านี้ไม่คาดคิดอย่างสมบูรณ์
(หมายเหตุ: พูดง่ายๆก็คือจริง:
อินเตอร์เฟส A {การทดสอบโมฆะเริ่มต้น () {}} อินเตอร์เฟส B ขยายการทดสอบ void {เริ่มต้น () {}} การทดสอบระดับสาธารณะใช้ b {การทดสอบโมฆะสาธารณะ () {b.super.test (); //a.super.test (); ข้อผิดพลาด }}แน่นอนถ้าคุณเขียนสิ่งนี้ผู้ใช้เลือกที่จะใช้อินเตอร์เฟส B อย่างแข็งขัน ตัวอย่างในบทความแนะนำคลาสพื้นฐานดังนั้นการเปลี่ยนแปลงที่ไม่เป็นทางการดูเหมือนจะเกิดขึ้นในห้องสมุดและคลาสพื้นฐาน แต่ในความเป็นจริงมันทำให้รหัสผู้ใช้ไม่สามารถรวบรวมได้)
น่าแปลกที่ Java ไม่ได้แยกแยะสิ่งนี้ในรันไทม์ ตัวตรวจสอบความถูกต้องของ JVM อนุญาตให้คลาสคอมไพล์เรียกใช้วิธี SimpleInput :: Foo แม้ว่าคลาสที่โหลดจะสืบทอดเวอร์ชันที่อัปเดตของ ThirdPartyBaseclass และใช้อินเทอร์เฟซคอมเพล็กซ์โดยปริยาย หากคุณต้องการตำหนิคุณสามารถตำหนิคอมไพเลอร์เท่านั้น (หมายเหตุ: พฤติกรรมคอมไพเลอร์และรันไทม์ไม่สอดคล้องกัน)
แล้วเราเรียนรู้อะไรจากมัน? พูดง่ายๆอย่าแทนที่วิธีเริ่มต้นของอินเทอร์เฟซดั้งเดิมในอินเทอร์เฟซอื่น อย่าเขียนใหม่ด้วยวิธีการเริ่มต้นอื่นและอย่าเขียนใหม่ด้วยวิธีนามธรรม ในระยะสั้นคุณควรระมัดระวังมากเมื่อใช้วิธีการเริ่มต้น แม้ว่าพวกเขาจะทำให้อินเทอร์เฟซของไลบรารีคอลเลกชันที่มีอยู่ของ Java ง่ายขึ้น แต่ก็ช่วยให้คุณสามารถเรียกใช้วิธีการในโครงสร้างการสืบทอดของคลาสซึ่งเพิ่มความซับซ้อนเป็นหลัก ก่อน Java 7 คุณต้องสำรวจลำดับชั้นของคลาสเชิงเส้นและดูรหัสการโทรจริง เมื่อคุณรู้สึกว่าคุณต้องการมันจริงๆให้ใช้วิธีการเริ่มต้น
ข้างต้นเป็นคำอธิบายโดยละเอียดว่าทำไมคุณควรใช้วิธีการเริ่มต้นของ Java 8 ด้วยความระมัดระวัง ฉันหวังว่ามันจะเป็นประโยชน์กับการเรียนรู้ของทุกคน