การเอาชนะเมธอดโดยส่งผ่านเป็นอาร์กิวเมนต์วัตถุคลาสย่อยที่คาดว่าจะมีประเภทซูเปอร์


12

ฉันแค่เรียนรู้ Java และไม่ใช่โปรแกรมเมอร์ที่ฝึกหัด

หนังสือที่ฉันกำลังติดตามกล่าวว่าเมื่อเอาชนะวิธีการประเภทอาร์กิวเมนต์จะต้องเหมือนกัน แต่ประเภทผลตอบแทนสามารถเข้ากันได้ polymorphically

คำถามของฉันคือทำไมข้อโต้แย้งที่ส่งไปยังวิธีการเอาชนะไม่เป็นประเภทย่อยของประเภทซุปเปอร์ที่คาดไว้

ในเมธอดโอเวอร์โหลดวิธีใดก็ตามที่ฉันเรียกใช้ออบเจ็กต์นั้นรับประกันว่าจะถูกกำหนดไว้บนออบเจ็กต์


หมายเหตุเกี่ยวกับรายการที่แนะนำ:

คำแนะนำแรกดูเหมือนจะเกี่ยวกับลำดับชั้นและสถานที่ที่จะนำการทำงาน คำถามของฉันเน้นที่ทำไมการ จำกัด ภาษาจึงมีอยู่มากขึ้น

ข้อเสนอแนะที่สองอธิบายถึงวิธีการที่จะทำสิ่งที่ฉันขอ แต่ไม่ได้ว่าทำไมมันจะต้องมีการกระทำที่ทาง คำถามของฉันเน้นที่สาเหตุ


1
ถามและตอบในคำถามก่อนหน้า : "โดยทั่วไปถือว่าเป็นความล้มเหลวของหลักการทดแทน Liskov (LSP) เนื่องจากข้อ จำกัด ที่เพิ่มทำให้การปฏิบัติการระดับฐานไม่เหมาะสมเสมอสำหรับคลาสที่ได้รับ ... "
gnat

1
ความเป็นไปได้ที่ซ้ำกันของการทำให้คลาสย่อยเฉพาะประเภทมากขึ้นด้วย accessors

@gnat คำถามไม่ได้ว่าต้องมีประเภทย่อยที่เฉพาะเจาะจงมากขึ้นสำหรับการขัดแย้งละเมิดหลักการคอมพิวเตอร์บางส่วนคำถามคือว่ามันเป็นไปได้ที่ edalorzo ซึ่งตอบ
user949300

คำตอบ:


18

แนวคิดที่คุณเริ่มอ้างถึงในคำถามของคุณเรียกว่าcovariant กลับประเภท

Covariant return types ทำงานได้เพราะวิธีการหนึ่งควรจะคืนค่าอ็อบเจกต์บางประเภทและเมธอดการแทนที่อาจส่งคืนคลาสย่อยของมัน บนพื้นฐานของกฎ Subtyping ของภาษาเช่น Java ถ้าSเป็นชนิดย่อยของTแล้วทุกที่ที่ปรากฏเราสามารถผ่านการTS

เช่นนี้จะปลอดภัยในการส่งคืนSเมื่อแทนที่เมธอดที่คาดTไว้

ข้อเสนอแนะของคุณเพื่อยอมรับว่าการแทนที่เมธอดใช้อาร์กิวเมนต์ที่เป็นชนิดย่อยของเมธอดที่ถูกร้องขอโดยเมธอด overridden มีความซับซ้อนมากขึ้นเนื่องจากนำไปสู่ความไม่แน่นอนในระบบพิมพ์

ด้วยมือข้างหนึ่งตามกฎการพิมพ์ย่อยที่กล่าวถึงข้างต้นส่วนใหญ่แล้วมันใช้ได้กับสิ่งที่คุณต้องการจะทำแล้ว ตัวอย่างเช่น

interface Hunter {
   public void hunt(Animal animal);
}

ไม่มีสิ่งใดขัดขวางการใช้งานในชั้นเรียนนี้จากการรับสัตว์ทุกชนิดมันเป็นไปตามเกณฑ์ในคำถามของคุณ

แต่สมมติว่าเราสามารถแทนที่วิธีนี้ตามที่คุณแนะนำ:

class MammutHunter implements Hunter {
  @Override
  public void hunt(Mammut animal) {
  }
}

นี่คือส่วนที่ตลกตอนนี้คุณสามารถทำได้:

AnimalHunter hunter = new MammutHunter();
hunter.hunt(new Bear()); //Uh oh

ตามอินเทอร์เฟซสาธารณะของAnimalHunterคุณควรจะสามารถล่าสัตว์ใด ๆ แต่ตามการใช้งานของMammutHunterคุณคุณยอมรับเฉพาะMammutวัตถุ ดังนั้นวิธี overriden ไม่ตอบสนองต่อส่วนต่อประสานสาธารณะ เราเพิ่งทำลายความสมบูรณ์ของระบบประเภทที่นี่

คุณสามารถใช้สิ่งที่คุณต้องการโดยใช้ข้อมูลทั่วไป

interface AnimalHunter<T extends Animal> {
   void hunt(T animal);
}

จากนั้นคุณสามารถกำหนด MammutHunter ของคุณ

class MammutHunter implements AnimalHunter<Mammut> {
   void hunt(Mammut m){
   }
}

และการใช้ความแปรปรวนร่วมแบบทั่วไปและความแปรปรวนร่วมคุณสามารถผ่อนคลายกฎในความโปรดปรานของคุณเมื่อจำเป็น ตัวอย่างเช่นเราสามารถตรวจสอบให้แน่ใจว่านักล่าสัตว์เลี้ยงลูกด้วยนมสามารถล่าสัตว์ได้ในบริบทที่กำหนด:

AnimalHunter<? super Feline> hunter = new MammalHunter();
hunter.hunt(new Lion());
hunter.hunt(new Puma());

เผื่อว่าการดำเนินการMammalHunterAnimalHunter<Mammal>

ในกรณีนี้จะไม่ได้รับการยอมรับ:

hunter.hunt(new Mammut()):

แม้เมื่อสัตว์เลี้ยงลูกด้วยนมเป็นสัตว์เลี้ยงลูกด้วยนมก็จะไม่ได้รับการยอมรับเนื่องจากข้อ จำกัด ในประเภทที่แตกต่างที่เราใช้อยู่ที่นี่ ดังนั้นคุณยังสามารถออกกำลังกายเพื่อควบคุมสิ่งต่าง ๆ เพื่อทำสิ่งที่คุณกล่าวถึง


3

ปัญหาไม่ใช่สิ่งที่คุณทำในวิธีการเอาชนะด้วยวัตถุที่กำหนดเป็นอาร์กิวเมนต์ ปัญหาคือสิ่งที่เป็นประเภทของข้อโต้แย้งรหัสโดยใช้วิธีการของคุณได้รับอนุญาตให้ฟีดกับวิธีการของคุณ

วิธีการแทนที่จะต้องทำตามสัญญาของวิธีการแทนที่ หากวิธีการแทนที่ยอมรับการขัดแย้งของบางคลาสและคุณแทนที่ด้วยวิธีการที่ยอมรับเฉพาะคลาสย่อยนั้นจะไม่ปฏิบัติตามสัญญา นั่นคือเหตุผลที่มันไม่ถูกต้อง

เอาชนะวิธีการที่มีประเภทเฉพาะเจาะจงมากขึ้นของการโต้แย้งที่เรียกว่ามากไป มันกำหนดวิธีการที่มีชื่อเดียวกัน แต่มีอาร์กิวเมนต์ที่แตกต่างกันหรือเฉพาะเจาะจงมากขึ้น วิธีการโอเวอร์โหลดมีอยู่นอกเหนือจากวิธีดั้งเดิม วิธีการใดเรียกว่าขึ้นอยู่กับชนิดที่รู้จักในเวลารวบรวม ในการโอเวอร์โหลดเมธอดคุณต้องปล่อยคำอธิบายประกอบ @Override

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.