สวัสดี! คุณใช้เมธอด Java อยู่แล้วและรู้เรื่องเหล่านี้มาก วิธีการแทนที่วิธีการทำงาน - 1แน่นอนว่าคุณเจอคลาสที่มีเมธอดมากมายที่มีชื่อเหมือนกัน แต่มีรายการอาร์กิวเมนต์ต่างกัน คุณจะจำได้ว่าในกรณีเหล่านั้นเราใช้วิธีโอเวอร์โหลด วันนี้เราจะมาดูสถานการณ์ที่แตกต่างกัน ลองนึกภาพว่าเรามีเมธอดทั่วไปวิธีหนึ่ง แต่มันควรทำสิ่งต่าง ๆ ขึ้นอยู่กับคลาสที่ถูกเรียกใช้ เราจะนำพฤติกรรมนี้ไปใช้อย่างไร เพื่อให้เข้าใจสิ่งนี้ ลองใช้Animalคลาสพาเรนต์ซึ่งเป็นตัวแทนของสัตว์ และสร้างspeakเมธอดในนั้น:
public class Animal {

   public void speak() {

       System.out.println("Hello!");
   }
}
แม้ว่าเราจะเพิ่งเริ่มเขียนโปรแกรม แต่คุณอาจเห็นปัญหาที่อาจเกิดขึ้นได้: โลกนี้เต็มไปด้วยสัตว์มากมาย และพวกมันทั้งหมด "พูด" ต่างกัน: แมวเหมียว เป็ดตัวเบ้อเร่อ งูขู่ฟ่อ ฯลฯ เป้าหมายของเรานั้นง่ายมาก: การแทนที่เมธอดทำงานอย่างไร - 2เรา ต้องการหลีกเลี่ยงการสร้างวิธีการพูดมากมาย แทนที่จะสร้างmeow()วิธีการร้องเหมียวhiss()ส่งเสียงฟู่ ฯลฯ เราต้องการให้งูส่งเสียงฟู่ แมวร้องเหมียว และสุนัขเห่าเมื่อspeak()เรียกวิธีการนี้ เราสามารถทำสิ่งนี้ให้สำเร็จได้โดยง่ายโดยใช้วิธีการ overriding วิกิพีเดียอธิบายคำศัพท์ดังต่อไปนี้: การแทนที่เมธอดในการเขียนโปรแกรมเชิงวัตถุเป็นคุณลักษณะทางภาษาที่อนุญาตให้คลาสย่อยหรือคลาสย่อยจัดเตรียมการใช้งานเฉพาะของเมธอดที่จัดเตรียมไว้แล้วโดยหนึ่งในซูเปอร์คลาสหรือคลาสพาเรนต์ ถูกต้องโดยพื้นฐานแล้ว การแทนที่ทำให้คุณสามารถใช้เมธอดของคลาสหลักและเขียนการใช้งานของคุณเองในแต่ละคลาสที่ได้รับมา การใช้งานใหม่ในคลาสลูก "แทนที่" คลาสในพาเรนต์ ลองดูตัวอย่างนี้ว่าเป็นอย่างไร มาสร้างลูกหลานของAnimalชั้นเรียนของเรา 4 คน:
public class Bear extends Animal {
   @Override
   public void speak() {
       System.out.println("Growl!");
   }
}
public class Cat extends Animal {

   @Override
   public void speak() {
       System.out.println("Meow!");
   }
}

public class Dog extends Animal {

   @Override
   public void speak() {
       System.out.println("Woof!");
   }
}


public class Snake extends Animal {

   @Override
   public void speak() {
       System.out.println("Hiss!");
   }
}
นี่คือเคล็ดลับเล็กๆ น้อยๆ สำหรับอนาคต: หากต้องการแทนที่เมธอดของคลาสพาเรนต์ ให้เข้าไปในโค้ดของคลาสที่ได้รับมาในIntelliJ IDEกดCtrl+Oแล้วเลือกOverride method...จากเมนู ทำความคุ้นเคยกับการใช้ปุ่มลัดตั้งแต่เริ่มต้น พวกเขาจะเร่งการเข้ารหัส! เพื่อให้ได้ลักษณะการทำงานที่ต้องการ เราทำบางสิ่ง:
  1. ในแต่ละคลาสที่สืบทอดมา เราสร้างเมธอดที่มีชื่อเดียวกับเมธอดในคลาสพาเรนต์
  2. เราบอกคอมไพเลอร์ว่าเราไม่ได้ให้ชื่อเมธอดเดียวกับในคลาสพาเรนต์ แต่เราต้องการแทนที่พฤติกรรมของมัน "ข้อความ" นี้ไปยังคอมไพเลอร์จะถูกส่งผ่านคำอธิบายประกอบ@Override
    คำอธิบายประกอบ @Override เหนือเมธอดจะบอกคอมไพเลอร์ (รวมถึงโปรแกรมเมอร์อื่นๆ ที่อ่านโค้ดของคุณ) ว่า "อย่ากังวล นี่ไม่ใช่ข้อผิดพลาดหรือการมองข้าม ฉันทราบดีว่ามีเมธอดนี้อยู่แล้ว และฉันต้องการแทนที่เมธอดนี้ .

  3. เราเขียนการนำไปใช้ที่เราต้องการสำหรับแต่ละคลาสที่สืบทอดมา เมื่อspeak()เรียกวิธีการนี้ งูควรขู่ หมีควรคำราม และอื่นๆ
มาดูกันว่ามันทำงานอย่างไรในโปรแกรม:
public class Main {

   public static void main(String[] args) {

       Animal animal1 = new Dog();
       Animal animal2 = new Cat();
       Animal animal3 = new Bear();
       Animal animal4 = new Snake();

       animal1.speak();
       animal2.speak();
       animal3.speak();
       animal4.speak();
   }
}
เอาต์พุตคอนโซล:

Woof! 
Meow! 
Growl! 
Hiss!
เยี่ยมมาก ทุกอย่างทำงานได้ตามปกติ! เราสร้างตัวแปรอ้างอิง 4 ตัวซึ่งมีประเภทเป็นAnimalคลาสพาเรนต์ และกำหนดออบเจกต์ที่แตกต่างกัน 4 ตัวของคลาสรองลงมา เป็นผลให้แต่ละวัตถุทำงานแตกต่างกัน สำหรับแต่ละคลาสที่ได้รับมา เมธอดที่ถูกแทนที่จะspeak()แทนที่speak()เมธอดที่มีอยู่ของAnimalคลาส (ซึ่งจะแสดง "Speaking: " บนคอนโซล) การแทนที่เมธอดทำงานอย่างไร - 3การแทนที่เมธอดมีข้อจำกัดหลายประการ:
  1. เมธอดที่ถูกแทนที่ต้องมีอาร์กิวเมนต์เดียวกันกับเมธอดในคลาสพาเรนต์

    หากspeakเมธอดของคลาสพาเรนต์รับ a Stringเป็นอินพุต ดังนั้นเมธอดที่ถูกแทนที่ในคลาสรองลงมาจะต้องรับ a Stringเป็นอินพุต ด้วย มิฉะนั้น คอมไพเลอร์จะสร้างข้อผิดพลาด:

    public class Animal {
    
       public void speak(String s) {
    
           System.out.println("Speaking: " + s);
       }
    }
    
    public class Cat extends Animal {
    
       @Override // Error!
       public void speak() {
           System.out.println("Meow!");
       }
    }

  2. เมธอดที่ถูกแทนที่ต้องมีประเภทการส่งคืนเหมือนกับเมธอดในคลาสพาเรนต์

    มิฉะนั้น เราจะได้รับข้อผิดพลาดในการรวบรวม:

    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    
    public class Cat extends Animal {
    
       @Override
       public String speak() {         // Error!
           System.out.println("Meow!");
           return "Meow!";
       }
    }

  3. ตัวดัดแปลงการเข้าถึงของเมธอดที่ถูกแทนที่จะต้องไม่แตกต่างจากตัวดั้งเดิม:

    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    public class Cat extends Animal {
    
       @Override
       private void speak() {      // Error!
           System.out.println("Meow!");
       }
    }
ใน Java การแทนที่เมธอดเป็นวิธีหนึ่งในการนำความหลากหลายไปใช้ นั่นหมายความว่าข้อได้เปรียบหลักของมันคือความยืดหยุ่นที่เราพูดถึงก่อนหน้านี้ เราสามารถสร้างลำดับชั้นของคลาสที่เรียบง่ายและมีเหตุผล โดยแต่ละคลาสจะมีพฤติกรรมเฉพาะ (หมาเห่า แมวเหมียว) แต่มีอินเทอร์เฟซเดียว — เป็นเมธอดเดียวspeak()สำหรับทุกคน แทนที่จะเป็นเมธอดต่างๆ เช่นbark(), meow()เป็นต้น