“อมิโก้ คุณชอบปลาวาฬไหม”
"ปลาวาฬเหรอ ไม่ ไม่เคยได้ยินชื่อพวกมันเลย"
"มันเหมือนวัว เพียงแต่ตัวใหญ่กว่าและว่ายน้ำได้ บังเอิญว่าวาฬมาจากวัว เอ่อ หรืออย่างน้อยพวกมันก็มีบรรพบุรุษร่วมกัน ไม่สำคัญหรอก"
"ฟังนะ ฉันอยากจะบอกคุณเกี่ยวกับเครื่องมือที่ทรงพลังอีกอย่างของ OOP: polymorphismซึ่งมีคุณสมบัติ 4 ประการ"
1) การเอาชนะวิธีการ
ลองนึกภาพว่าคุณเขียนคลาส "Cow" สำหรับเกม มีตัวแปรและเมธอดของสมาชิกมากมาย วัตถุในชั้นนี้สามารถทำสิ่งต่างๆ ได้: เดิน, กิน, นอน วัวยังสั่นกระดิ่งเมื่อพวกเขาเดิน สมมติว่าคุณได้ดำเนินการทุกอย่างในชั้นเรียนจนถึงรายละเอียดที่เล็กที่สุด
ทันใดนั้นลูกค้าบอกว่าเขาต้องการเปิดตัวเกมระดับใหม่ซึ่งการกระทำทั้งหมดเกิดขึ้นในทะเลและตัวละครหลักคือปลาวาฬ
คุณเริ่มออกแบบคลาส Whale และตระหนักว่ามันแตกต่างจากคลาส Cow เพียงเล็กน้อยเท่านั้น ทั้งสองคลาสใช้ตรรกะที่คล้ายกันมาก และคุณตัดสินใจใช้การสืบทอด
คลาส Cow เหมาะสมอย่างยิ่งที่จะเป็นคลาสพาเรนต์: มันมีตัวแปรและเมธอดที่จำเป็นทั้งหมดอยู่แล้ว สิ่งที่คุณต้องทำคือเพิ่มความสามารถในการว่ายน้ำของวาฬ แต่มีปัญหา: วาฬของคุณมีขา มีเขา และมีกระดิ่ง ท้ายที่สุดคลาส Cow ใช้ฟังก์ชันนี้ คุณทำอะไรได้บ้าง?
วิธีการเอาชนะมาช่วย หากเราสืบทอดเมธอดที่ไม่ได้ทำตามที่เราต้องการในคลาสใหม่ เราสามารถแทนที่เมธอดด้วยเมธอดอื่นได้
สิ่งนี้ทำได้อย่างไร? ในคลาสที่สืบทอดมา เราประกาศเมธอดที่เราต้องการเปลี่ยน (โดยมีลายเซ็นเมธอดเดียวกับในคลาสพาเรนต์ ) จากนั้นเราเขียนโค้ดใหม่สำหรับวิธีการ แค่นั้นแหละ. ราวกับว่าไม่มีเมธอดเก่าของคลาสพาเรนต์อยู่
นี่คือวิธีการทำงาน:
รหัส | คำอธิบาย |
---|---|
|
ที่นี่เรากำหนดสองคลาส : Cow และ สืบทอด _Whale Whale Cow
คลาส |
|
รหัสนี้แสดง « ฉันเป็นวัว » บนหน้าจอ |
|
รหัสนี้แสดง « ฉันเป็นปลาวาฬ » บนหน้าจอ |
หลังจากสืบทอดCow
และแทนที่printName
คลาสWhale
จะมีข้อมูลและวิธีการดังต่อไปนี้:
รหัส | คำอธิบาย |
---|---|
|
เราไม่รู้อะไรเลยเกี่ยวกับวิธีการแบบเก่า |
"พูดตามตรง นั่นคือสิ่งที่ฉันคาดหวังไว้"
2) แต่นั่นไม่ใช่ทั้งหมด
"สมมติว่า Cow
คลาสมี printAll
, เมธอดที่เรียกใช้เมธอดอื่นอีกสองเมธอด จากนั้นโค้ดจะทำงานดังนี้:"
หน้าจอจะแสดง:
ฉันขาว
ฉันเป็นปลาวาฬ
รหัส | คำอธิบาย |
---|---|
|
|
|
หน้าจอจะแสดง: ฉันขาว ฉันเป็นปลาวาฬ |
โปรดทราบว่าเมื่อเมธอด printAll () ของคลาส Cow ถูกเรียกบนวัตถุ Whale จะใช้วิธี printName() ของ Whaleไม่ใช่ของ Cow
สิ่งสำคัญไม่ใช่คลาสที่เขียนเมธอด แต่เป็นประเภท (คลาส) ของออบเจกต์ที่เรียกใช้เมธอด
"ฉันเห็น."
"คุณสามารถสืบทอดและแทนที่เมธอดที่ไม่ใช่สแตติกเท่านั้น เมธอดสแตติกไม่ได้รับการสืบทอด ดังนั้นจึงไม่สามารถแทนที่ได้"
นี่คือลักษณะของคลาส Whale หลังจากที่เราใช้การสืบทอดและแทนที่เมธอด:
รหัส | คำอธิบาย |
---|---|
|
นี่คือลักษณะของคลาส Whale หลังจากที่เราใช้การสืบทอดและแทนที่เมธอด เราไม่รู้อะไรเลยเกี่ยวกับprintName วิธีการ เก่าๆ |
3) การหล่อแบบ
นี่เป็นประเด็นที่น่าสนใจยิ่งกว่า เนื่องจากคลาสสืบทอดเมธอดและข้อมูลทั้งหมดของคลาสพาเรนต์ อ็อบเจกต์ของคลาสนี้สามารถอ้างอิงโดยตัวแปรของคลาสพาเรนต์ (และพาเรนต์ของพาเรนต์ ฯลฯ จนถึงคลาสอ็อบเจกต์) พิจารณาตัวอย่างนี้:
รหัส | คำอธิบาย |
---|---|
|
หน้าจอจะแสดง: ฉันเป็นคนผิวขาว |
|
หน้าจอจะแสดง: ฉันเป็นคนผิวขาว |
|
หน้าจอจะแสดง: Whale@da435a เมธอด toString() สืบทอดมาจากคลาสอ็อบเจกต์ |
"ของดี แต่ทำไมคุณถึงต้องการสิ่งนี้"
"มันเป็นคุณสมบัติที่มีค่า คุณจะเข้าใจในภายหลังว่ามันมีค่ามาก มีค่ามาก"
4) การรวมล่าช้า (การจัดส่งแบบไดนามิก)
นี่คือสิ่งที่ดูเหมือน:
รหัส | คำอธิบาย |
---|---|
|
หน้าจอจะแสดง: ฉันเป็นปลาวาฬ |
|
หน้าจอจะแสดง: ฉันเป็นปลาวาฬ |
โปรดทราบว่าไม่ใช่ประเภทของตัวแปรที่กำหนดว่า เมธอด printName ใด ที่เราเรียก (ของคลาส Cow หรือ Whale) แต่เป็นประเภทของวัตถุที่ตัวแปรอ้างอิง
ตัวแปร Cow เก็บการอ้างอิงถึง วัตถุ Whaleและ เมธอด printNameที่กำหนดไว้ในคลาสWhaleจะถูกเรียก
"พวกเขาไม่ได้เพิ่มสิ่งนั้นเพื่อความชัดเจน"
“ใช่ มันไม่ชัดเจนขนาดนั้น จำกฎสำคัญนี้ไว้:”
ชุดของเมธอดที่คุณสามารถเรียกใช้ตัวแปรได้นั้นถูกกำหนดโดยประเภทของตัวแปร แต่เมธอด/การใช้งานเฉพาะใดที่ถูกเรียกจะถูกกำหนดโดยประเภท/คลาสของออบเจกต์ที่ตัวแปรอ้างอิง
"ฉันจะพยายาม."
"คุณจะพบสิ่งนี้อย่างต่อเนื่อง ดังนั้นคุณจะเข้าใจได้อย่างรวดเร็วและไม่มีวันลืม"
5) ประเภทหล่อ
การแคสต์ทำงานแตกต่างกันสำหรับประเภทการอ้างอิง เช่น คลาส ซึ่งแตกต่างจากประเภทดั้งเดิม อย่างไรก็ตามการแปลงที่กว้างขึ้นและแคบลงใช้กับประเภทการอ้างอิงด้วย พิจารณาตัวอย่างนี้:
ขยับขยายแปลง | คำอธิบาย |
---|---|
|
การแปลงขยายแบบคลาสสิก ตอนนี้คุณสามารถเรียกใช้เมธอดที่กำหนดในคลาส Cow บนวัตถุ Whale เท่านั้น คอมไพเลอร์จะให้คุณใช้ตัวแปร cowเพื่อเรียกเมธอดที่กำหนดโดยประเภท Cow เท่านั้น |
การแปลงที่แคบลง | คำอธิบาย |
---|---|
|
การแปลงแบบคลาสสิกที่แคบลงพร้อมการตรวจสอบประเภท ตัวแปรcowประเภท Cow เก็บการอ้างอิงถึงวัตถุ Whale เราตรวจสอบว่าเป็นกรณีนี้จากนั้นทำการแปลงประเภท (ขยาย) สิ่งนี้เรียกว่าการหล่อแบบ |
|
คุณยังสามารถทำการแปลงประเภทการอ้างอิงให้แคบลงโดยไม่ต้องตรวจสอบประเภทวัตถุ ในกรณีนี้ หาก ตัวแปร cowชี้ไปที่สิ่งอื่นที่ไม่ใช่วัตถุ Whale ข้อยกเว้น (InvalidClassCastException) จะถูกส่งออกไป |
6) และตอนนี้สำหรับของอร่อย เรียกวิธีเดิม.
บางครั้งเมื่อแทนที่เมธอดที่สืบทอดมา คุณไม่ต้องการแทนที่เมธอดทั้งหมด บางครั้งคุณแค่ต้องการเพิ่มเล็กน้อยลงไป
ในกรณีนี้ คุณต้องการให้โค้ดของเมธอดใหม่เรียกเมธอดเดิม แต่เรียกในคลาสพื้นฐาน และ Java ให้คุณทำสิ่งนี้ นี่คือวิธีการดำเนินการ: super.method()
.
นี่คือตัวอย่างบางส่วน:
รหัส | คำอธิบาย |
---|---|
|
|
|
หน้าจอจะแสดง: ฉันเป็นคนผิวขาว นี่เป็นเท็จ: ฉันเป็นวัว ฉันเป็นปลาวาฬ |
"อืม นั่นคือบทเรียน หูหุ่นยนต์ของฉันแทบจะละลาย"
"ใช่ นี่ไม่ใช่เนื้อหาง่ายๆ เป็นเนื้อหาที่ยากที่สุดที่คุณจะพบ อาจารย์สัญญาว่าจะให้ลิงก์ไปยังเนื้อหาจากผู้เขียนคนอื่น ดังนั้นหากคุณยังไม่เข้าใจบางสิ่ง คุณสามารถกรอกข้อมูลลงใน ช่องว่าง"
GO TO FULL VERSION