การสืบทอดเป็นแนวคิดที่สำคัญในเชิงวัตถุ การสืบทอดเป็นอีกวิธีที่สำคัญในการปรับปรุงการนำโค้ดกลับมาใช้ใหม่ได้นอกเหนือจากการจัดองค์ประกอบ เราเห็นในการจัดองค์ประกอบว่าการจัดองค์ประกอบเป็นส่วนต่อประสานการทำงานของวัตถุที่ถูกเรียกซ้ำ ๆ ดังที่เราจะได้เห็น การสืบทอดช่วยให้คุณสามารถนำคำจำกัดความของคลาสที่มีอยู่กลับมาใช้ใหม่ได้
มรดกชั้นเรียน
เมื่อเรากำหนดคลาสก่อนหน้านี้ เราเริ่มต้นจากศูนย์และกำหนดสมาชิกแต่ละคนของคลาสโดยละเอียด ตัวอย่างเช่น คลาสมนุษย์ต่อไปนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
คลาสมนุษย์
-
-
*อุปกรณ์เสริม
-
สาธารณะ int getHeight()
-
กลับ this.height;
-
-
* มิวเทเตอร์
-
โมฆะสาธารณะ growHeight (int h)
-
this.height = this.height + h;
-
-
*ลมหายใจ
-
ลมหายใจเป็นโมฆะสาธารณะ ()
-
System.out.println("hu...hu...");
-
ความสูง int ส่วนตัว
-
จากคำจำกัดความของคลาสข้างต้น เราสามารถเข้าใจรายละเอียดทั้งหมดของคลาสได้: ข้อมูลสมาชิกของคลาส วิธีการของคลาส และอินเทอร์เฟซของคลาส
ตอนนี้เราต้องกำหนดคลาสใหม่ เช่น คลาส Woman และสมมติว่า Woman ค่อนข้างคล้ายกับคลาส Human:
มนุษย์และผู้หญิง
เราสามารถเริ่มต้นจากศูนย์และกำหนดคลาส Woman ได้อย่างสมบูรณ์เหมือนเมื่อก่อน:
คัดลอกรหัสรหัสดังต่อไปนี้:
ผู้หญิงชั้น
-
-
*อุปกรณ์เสริม
-
สาธารณะ int getHeight()
-
กลับ this.height;
-
-
* มิวเทเตอร์
-
โมฆะสาธารณะ growHeight (int h)
-
this.height = this.height + h;
-
-
*ลมหายใจ
-
ลมหายใจเป็นโมฆะสาธารณะ ()
-
System.out.println("hu...hu...");
-
-
* วิธีการใหม่
-
ให้มนุษย์สาธารณะ ()
-
System.out.println("ให้กำเนิด");
กลับ (มนุษย์ใหม่ (20));
-
ความสูง int ส่วนตัว
-
โปรแกรมเมอร์จะมีปัญหามากมายเมื่อเขียนโปรแกรมข้างต้น มีการเขียนคำจำกัดความไว้มากมายในคลาส Human แต่เราต้องพิมพ์ใหม่อีกครั้ง คลาส Woman เพิ่มเมธอด GiveBirth() ใหม่เท่านั้น (เมธอดนี้จะสร้างและส่งกลับอ็อบเจ็กต์ Human ใหม่)
การใช้การสืบทอดเราสามารถหลีกเลี่ยงการทำซ้ำข้างต้นได้ ปล่อยให้คลาส Woman สืบทอดมาจากคลาส Human และคลาส Woman จะมีฟังก์ชันของสมาชิกสาธารณะทั้งหมดในคลาส Human โดยอัตโนมัติ
เราใช้คำหลักขยายเพื่อระบุการสืบทอด:
คัดลอกรหัสรหัสดังต่อไปนี้:
ผู้หญิงชั้นขยายมนุษย์
-
-
* วิธีการใหม่
-
ให้มนุษย์สาธารณะ ()
-
System.out.println("ให้กำเนิด");
กลับ (มนุษย์ใหม่ (20));
-
-
ด้วยวิธีนี้ เราจึงประหยัดการพิมพ์ได้มาก เราสร้างคลาสใหม่ผ่านการสืบทอด เรียกว่าคลาสที่ได้รับ คลาสที่สืบทอดมา (มนุษย์) เรียกว่าคลาสฐาน (คลาสฐาน) คลาสที่ได้รับใช้คลาสฐานเป็นพื้นฐานสำหรับคำจำกัดความของตัวเอง และเสริมเมธอด GiveBirth() ที่ไม่ได้กำหนดไว้ในคลาสฐาน ความสัมพันธ์ทางมรดกสามารถแสดงเป็น:
การสืบทอด: ลูกศรชี้ไปที่คลาสพื้นฐาน
คุณสามารถใช้คลาสทดสอบต่อไปนี้เพื่อทดสอบ:
คัดลอกรหัสรหัสดังต่อไปนี้:
การทดสอบในชั้นเรียนสาธารณะ
-
โมฆะสาธารณะคง main (String [] args)
-
ผู้หญิง aWoman = ผู้หญิงใหม่ ();
aWoman.growHeight(120);
System.out.println(aWoman.getHeight());
-
-
เลเยอร์ที่ได้รับ
เราสร้างคลาส Woman ผ่านการสืบทอด กระบวนการทั้งหมดสามารถแบ่งออกเป็นสามระดับ: คำจำกัดความของคลาสพื้นฐาน คำจำกัดความของคลาสที่ได้รับ และการใช้งานภายนอก
ระดับของคำจำกัดความคลาสพื้นฐานคือการกำหนดคลาสตามปกติ เช่น คำจำกัดความคลาสมนุษย์ด้านบน
จากมุมมองของผู้ใช้ภายนอก (เช่น อ็อบเจ็กต์คลาส Woman ที่สร้างขึ้นในคลาส Test) คลาสที่ได้รับมีอินเทอร์เฟซภายนอกแบบรวม:
สำหรับผู้ใช้ภายนอก อินเทอร์เฟซข้างต้นก็เพียงพอแล้ว จากมุมมองของอินเทอร์เฟซเพียงอย่างเดียว ไม่มีอะไรพิเศษเกี่ยวกับคลาสที่ได้รับ
อย่างไรก็ตาม โปรแกรมเมอร์จะต้องระมัดระวังเมื่อทำงานในระดับคำจำกัดความคลาสที่ได้รับ:
ขั้นแรก อินเทอร์เฟซจะถูกผสม: เมธอด getHeight() และ growHeight() มาจากคลาสพื้นฐาน ในขณะที่เมธอด GiveBirth() ถูกกำหนดไว้ภายในคลาสที่ได้รับ
มีภาวะแทรกซ้อนเพิ่มเติม ก่อนหน้านี้เราสามารถเข้าถึงสมาชิกของคลาสภายในคลาสได้อย่างอิสระ (ใช้สิ่งนี้เพื่ออ้างถึงวัตถุ) อย่างไรก็ตาม เมื่อเราอยู่ในขอบเขตคำจำกัดความของคลาส Woman เราจะไม่สามารถเข้าถึงสมาชิกส่วนตัวของคลาสพื้นฐาน Human ได้ เราจำความหมายของคำว่าส่วนตัวได้: สมาชิกส่วนตัวมีไว้สำหรับใช้ภายในชั้นเรียนเท่านั้น คลาส Woman เป็นคลาสใหม่ที่แตกต่างจากคลาส Human ดังนั้นจึงตั้งอยู่นอกคลาส Human ในคลาสที่ได้รับ สมาชิกส่วนตัวของคลาสพื้นฐานไม่สามารถเข้าถึงได้
แต่สิ่งที่น่าสนใจคือเมธอด growHeight() และ getHeight() ของเรายังคงใช้งานได้ นี่แสดงว่ามีสมาชิกส่วนตัวของคลาสพื้นฐานอยู่ เราไม่สามารถเข้าถึงได้โดยตรง
เพื่อชี้แจงแนวคิด เราจำเป็นต้องเข้าใจกลไกการสร้างของคลาสอ็อบเจ็กต์ที่ได้รับ เมื่อเราสร้างอ็อบเจ็กต์ของคลาสที่ได้รับ Java จะสร้างอ็อบเจ็กต์คลาสพื้นฐาน (subobject) ก่อน และเพิ่มสมาชิกอื่น ๆ ที่กำหนดโดยคลาสที่ได้รับนั้นประกอบขึ้นเป็นอ็อบเจ็กต์คลาสที่ได้รับ สิ่งที่ผู้ใช้ภายนอกสามารถเห็นได้คือสมาชิกสาธารณะของคลาสพื้นฐานและคลาสที่ได้รับ ดังที่แสดงด้านล่าง:
วัตถุคลาสฐานและวัตถุคลาสที่ได้รับ
สีเหลืองในภาพคือวัตถุคลาสพื้นฐาน สมาชิกของชั้นฐานสามารถเข้าถึงกันและกันได้ (ใช้สิ่งนี้ในคำจำกัดความคลาสมนุษย์เพื่ออ้างถึงอ็อบเจ็กต์คลาสฐาน)
ส่วนสีน้ำเงินคือเนื้อหาใหม่ของวัตถุที่ได้รับ ฉันเรียกส่วนนี้ว่าเลเยอร์ที่ได้รับ ส่วนสีน้ำเงินและสีเหลืองรวมกันเป็นวัตถุที่ได้รับ สมาชิกของเลเยอร์ที่ได้รับสามารถเข้าถึงได้ (ซึ่งอยู่ในคำจำกัดความของผู้หญิง) นอกจากนี้เรายังสามารถเข้าถึงสมาชิกสาธารณะของชั้นฐานได้อีกด้วย ด้วยเหตุนี้ เราจึงใช้คีย์เวิร์ด super เพื่ออ้างถึงอ็อบเจ็กต์คลาสพื้นฐาน และใช้ super.member เพื่อเป็นตัวแทนของสมาชิกฐาน (สาธารณะ)
เมื่อเราอยู่ในเลเยอร์ที่ได้รับ (นั่นคือ เมื่อกำหนดคลาส Woman) เราไม่สามารถเข้าถึงสมาชิกส่วนตัวฐานสีแดงได้ เมื่อเราออกไปข้างนอก เราไม่สามารถเข้าถึงสมาชิกส่วนตัวในเลเยอร์ที่ได้รับสีม่วงหรือสมาชิกส่วนตัวในเลเยอร์ฐานสีแดงได้
(สมาชิกส่วนตัวของเลเยอร์ที่ได้รับมีข้อจำกัดในการเข้าถึง ดังนั้นจึงถูกทำเครื่องหมายด้วยเครื่องหมายทับ สมาชิกส่วนตัวของเลเยอร์ฐานมีข้อจำกัดในการเข้าถึงมากที่สุด ดังนั้นจึงถูกทำเครื่องหมายด้วยเครื่องหมายทับ)
Super คล้ายกับสิ่งนี้และเป็นพารามิเตอร์โดยนัยด้วย เมื่อเราอยู่ในระดับที่แตกต่างกันของคำจำกัดความของคลาสนี้ก็จะมีความหมายที่แตกต่างกัน โปรดระวังคำนี้และคำสำคัญขั้นสูง
(Java ไม่ได้บังคับให้ใช้ this และ super Java สามารถระบุความเป็นเจ้าของสมาชิกได้โดยอัตโนมัติในหลาย ๆ กรณี แต่ฉันคิดว่านี่เป็นแนวทางปฏิบัติที่ดี)
ได้รับการคุ้มครอง
ก่อนหน้านี้เราได้แนะนำคำสำคัญที่เกี่ยวข้องกับสิทธิ์การเข้าถึงสองคำ ได้แก่ ส่วนตัวและสาธารณะ ซึ่งควบคุมการเปิดเผยภายนอกของสมาชิก ตอนนี้ เราขอแนะนำคีย์เวิร์ดการเข้าถึงใหม่: ป้องกัน
สมาชิกที่ทำเครื่องหมายว่าป้องกันจะมองเห็นได้ในคลาสนี้และคลาสที่ได้รับ แนวคิดนี้ง่ายต่อการเข้าใจ กล่าวคือ สมาชิกที่ได้รับการป้องกันของคลาสพื้นฐานสามารถเข้าถึงได้โดยเลเยอร์ที่ได้รับ แต่ไม่สามารถเข้าถึงได้จากภายนอก ดังที่แสดงด้านล่าง:
แทนที่วิธีการ
อินเทอร์เฟซภายนอกของวัตถุคลาสที่ได้รับในท้ายที่สุดจะประกอบด้วยสมาชิกสาธารณะของวัตถุคลาสฐานและสมาชิกสาธารณะของเลเยอร์ที่ได้รับ หากสมาชิกสาธารณะของคลาสพื้นฐานและสมาชิกสาธารณะของเลเยอร์ที่ได้รับมีชื่อเหมือนกัน ชื่อใดจะแสดงในอินเทอร์เฟซ Java
เราได้กล่าวไปแล้วในตัวสร้างและเมธอดโอเวอร์โหลดว่า Java ใช้ทั้งชื่อเมธอดและรายการพารามิเตอร์เพื่อกำหนดวิธีการที่จะเรียกใช้ วิธีการถูกกำหนดโดยชื่อวิธีการและรายการพารามิเตอร์ ในปัญหาข้างต้น หากชื่อเมธอดเหมือนกันแต่รายการพารามิเตอร์ต่างกัน ทั้งสองเมธอดจะถูกนำเสนอต่ออินเทอร์เฟซพร้อมกัน ซึ่งจะไม่ทำให้เราเกิดปัญหาใดๆ เมื่อทำการเรียกภายนอก Java จะตัดสินใจว่าจะใช้วิธีใด (วิธีการโอเวอร์โหลด) ตามพารามิเตอร์ที่ให้มา
จะเกิดอะไรขึ้นถ้าชื่อวิธีการและรายการพารามิเตอร์เหมือนกัน? เมื่อได้รับเลเยอร์ เรายังสามารถใช้ super และสิ่งนี้เพื่อพิจารณาว่าเป็นวิธีการใด เมื่ออยู่ภายนอก เราจะนำเสนอเฉพาะอินเทอร์เฟซแบบรวมเท่านั้น ดังนั้นเราจึงไม่สามารถจัดเตรียมสองวิธีพร้อมกันได้ ในกรณีนี้ Java จะแสดงวิธีการเลเยอร์ที่ได้รับแทนวิธีการเลเยอร์ฐาน
กลไกนี้เรียกว่าการเอาชนะวิธีการ การแทนที่เมธอดสามารถนำไปใช้ประโยชน์ได้ดีในการแก้ไขเมธอดของสมาชิกคลาสพื้นฐาน ตัวอย่างเช่น ในเลเยอร์ที่ได้รับ นั่นคือ เมื่อกำหนด Woman คุณสามารถแก้ไขเมธอด Breath() ที่ได้รับจากคลาสพื้นฐานได้:
คัดลอกรหัสรหัสดังต่อไปนี้:
ผู้หญิงชั้นขยายมนุษย์
-
* วิธีการใหม่
-
ให้มนุษย์สาธารณะ ()
-
System.out.println("ให้กำเนิด");
กลับ (มนุษย์ใหม่ (20));
-
-
* แทนที่ Human.breath()
-
ลมหายใจเป็นโมฆะสาธารณะ ()
-
ซุปเปอร์.ลมหายใจ();
System.out.println("su...");
-
-
โปรดทราบว่าขณะนี้เราอยู่ในเลเยอร์ที่ได้รับและยังสามารถเรียกใช้เมธอด Breath() ของออบเจ็กต์คลาสฐานผ่าน super ได้ เมื่อเราเรียกคลาส Woman จากภายนอก เนื่องจากการแทนที่เมธอด เราไม่สามารถเรียกเมธอดของอ็อบเจ็กต์คลาสฐานได้อีกต่อไป
การแทนที่วิธีการรักษาอินเทอร์เฟซของวัตถุคลาสฐานและใช้การดำเนินการของเลเยอร์ที่ได้รับ
ตัวสร้าง
หลังจากทำความเข้าใจแนวคิดของอ็อบเจ็กต์คลาสพื้นฐานและเลเยอร์ที่ได้รับแล้ว วิธีการก่อสร้างคลาสที่ได้รับจะเข้าใจได้ง่ายขึ้น
เราจำเป็นต้องกำหนดคอนสตรัคเตอร์ที่มีชื่อเดียวกันกับคลาสในคำจำกัดความของคลาสที่ได้รับ ในตัวสร้างนี้:
1. เนื่องจากอ็อบเจ็กต์คลาสฐานถูกสร้างและเตรียมใช้งานก่อนเมื่อสร้างอ็อบเจ็กต์ที่ได้รับ จึงควรเรียกตัวสร้างของคลาสฐานก่อน เราสามารถใช้คำสั่ง super(argument list) เพื่อเรียก Constructor ของคลาสพื้นฐานได้
2. หลังจากสร้างออบเจ็กต์คลาสฐานแล้ว ให้เริ่มสร้างเลเยอร์ที่ได้รับ (เริ่มต้นสมาชิกเลเยอร์ที่ได้รับ) เช่นเดียวกับวิธีการก่อสร้างทั่วไป โดยอ้างอิงถึงวิธีการก่อสร้างและวิธีการบรรทุกเกินพิกัด
ตัวอย่างเช่น ในโปรแกรมต่อไปนี้ คลาส Human มีตัวสร้าง:
คัดลอกรหัสรหัสดังต่อไปนี้:
คลาสมนุษย์
-
-
* ตัวสร้าง
-
มนุษย์สาธารณะ(int h)
-
นี่.ความสูง = h;
-
-
*อุปกรณ์เสริม
-
สาธารณะ int getHeight()
-
กลับ this.height;
-
-
* มิวเทเตอร์
-
โมฆะสาธารณะ growHeight (int h)
-
this.height = this.height + h;
-
-
*ลมหายใจ
-
ลมหายใจเป็นโมฆะสาธารณะ ()
-
System.out.println("hu...hu...");
-
ความสูง int ส่วนตัว
-
คำจำกัดความของคลาส Woman ที่ได้รับและวิธีการสร้าง:
คัดลอกรหัสรหัสดังต่อไปนี้:
ผู้หญิงชั้นขยายมนุษย์
-
-
* ตัวสร้าง
-
สาธารณะ ผู้หญิง(int h)
-
super(h); // ตัวสร้างคลาสพื้นฐาน
System.out.println("สวัสดีแพนโดร่า!");
-
-
* วิธีการใหม่
-
ให้มนุษย์สาธารณะ ()
-
System.out.println("ให้กำเนิด");
กลับ (มนุษย์ใหม่ (20));
-
-
* แทนที่ Human.breath()
-
ลมหายใจเป็นโมฆะสาธารณะ ()
-
ซุปเปอร์.ลมหายใจ();
System.out.println("su...");
-
-
สรุป
ขยาย
วิธีการเอาชนะ
ได้รับการคุ้มครอง
super.สมาชิก ซุปเปอร์()