JavaRush /จาวาบล็อก /Random-TH /ความแตกต่างในชวา

ความแตกต่างในชวา

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

ความแตกต่างคืออะไร?

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

ความแตกต่างใน Java ในการสัมภาษณ์ - 1
เราสามารถเริ่มต้นด้วยความจริงที่ว่าแนวทาง OOP เกี่ยวข้องกับการสร้างโปรแกรม Java ตามการโต้ตอบของวัตถุที่ยึดตามคลาส คลาสคือภาพวาดที่เขียนไว้ล่วงหน้า (เทมเพลต) ตามวัตถุที่จะสร้างในโปรแกรม ยิ่งไปกว่านั้น คลาสจะต้องมีประเภทเฉพาะเสมอ ซึ่งด้วยรูปแบบการเขียนโปรแกรมที่ดี จะช่วย “บอก” วัตถุประสงค์ของคลาสด้วยชื่อของมัน นอกจากนี้ สังเกตได้ว่าเนื่องจาก Java เป็นภาษาที่พิมพ์ยาก โค้ดโปรแกรมจึงต้องระบุประเภทของอ็อบเจ็กต์เสมอเมื่อประกาศตัวแปร นอกจากนี้ การพิมพ์ที่เข้มงวดยังช่วยเพิ่มความปลอดภัยของโค้ดและความน่าเชื่อถือของโปรแกรม และช่วยให้คุณป้องกันข้อผิดพลาดเกี่ยวกับความไม่เข้ากันของประเภท (เช่น ความพยายามที่จะแบ่งสตริงด้วยตัวเลข) ในขั้นตอนการคอมไพล์ โดยปกติแล้วคอมไพลเลอร์จะต้อง "รู้" ประเภทที่ประกาศ - นี่อาจเป็นคลาสจาก JDK หรือคลาสที่เราสร้างขึ้นเอง โปรดทราบสำหรับผู้สัมภาษณ์ว่าเมื่อทำงานกับโค้ดโปรแกรม เราสามารถใช้ไม่เพียงแต่อ็อบเจ็กต์ประเภทที่เรากำหนดเมื่อประกาศ แต่ยังรวมถึงรายการสืบทอดด้วย นี่เป็นจุดสำคัญ:เราสามารถปฏิบัติต่อหลายประเภทเสมือนว่าเป็นเพียงหนึ่งเดียว (ตราบใดที่ประเภทเหล่านั้นได้มาจากประเภทพื้นฐาน) นี่ก็หมายความว่าเมื่อมีการประกาศตัวแปรประเภทซูเปอร์คลาสแล้ว เราสามารถกำหนดค่าของหนึ่งในลูกหลานของมันให้กับตัวแปรได้ ผู้สัมภาษณ์จะชอบถ้าคุณยกตัวอย่าง เลือกออบเจ็กต์บางอย่างที่สามารถเป็นแบบทั่วไป (ฐาน) สำหรับกลุ่มของออบเจ็กต์และสืบทอดคลาสสองสามคลาสจากนั้น คลาสพื้นฐาน:
public class Dancer {
    private String name;
    private int age;

    public Dancer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void dance() {
        System.out.println(toString() + "I dance like everyone else.");
    }

    @Override
    public String toString() {
        return "Я " + name + ", to me " + age + " years. " ;
    }
}
ในลูกหลาน แทนที่วิธีการเรียนพื้นฐาน:
public class ElectricBoogieDancer extends Dancer {
    public ElectricBoogieDancer(String name, int age) {
        super(name, age);
    }
// overriding the base class method
    @Override
    public void dance() {
        System.out.println( toString() + "I dance electric boogie!");
    }
}

public class BreakDankDancer extends Dancer{

    public BreakDankDancer(String name, int age) {
        super(name, age);
    }
// overriding the base class method
    @Override
    public void dance(){
        System.out.println(toString() + "I'm breakdancing!");
    }
}
ตัวอย่างของความหลากหลายใน Java และการใช้วัตถุในโปรแกรม:
public class Main {

    public static void main(String[] args) {
        Dancer dancer = new Dancer("Anton", 18);

        Dancer breakDanceDancer = new BreakDankDancer("Alexei", 19);// upcast to base type
        Dancer electricBoogieDancer = new ElectricBoogieDancer("Igor", 20); // upcast to base type

        List<Dancer> discotheque = Arrays.asList(dancer, breakDanceDancer, electricBoogieDancer);
        for (Dancer d : discotheque) {
            d.dance();// polymorphic method call
        }
    }
}
mainแสดง ในรหัสวิธีการ ว่ามีอะไรอยู่ในบรรทัด:
Dancer breakDanceDancer = new BreakDankDancer("Alexei", 19);
Dancer electricBoogieDancer = new ElectricBoogieDancer("Igor", 20);
เราประกาศตัวแปรประเภทซูเปอร์คลาสและกำหนดค่าของหนึ่งในลูกหลาน เป็นไปได้มากว่าคุณจะถูกถามว่าทำไมคอมไพเลอร์ถึงไม่บ่นเกี่ยวกับความไม่ตรงกันระหว่างประเภทที่ประกาศทางด้านซ้ายและด้านขวาของเครื่องหมายมอบหมายเนื่องจาก Java มีการพิมพ์ที่เข้มงวด อธิบายว่าการแปลงประเภทขาขึ้นใช้งานได้ที่นี่ - การอ้างอิงถึงออบเจ็กต์จะถูกตีความว่าเป็นการอ้างอิงถึงคลาสฐาน ยิ่งไปกว่านั้น คอมไพลเลอร์เมื่อพบโครงสร้างดังกล่าวในโค้ด จะทำสิ่งนี้โดยอัตโนมัติและโดยปริยาย จากโค้ดตัวอย่าง แสดงให้เห็นว่าประเภทคลาสที่ประกาศทางด้านซ้ายของป้ายมอบหมายมีDancerหลายรูปแบบ (ประเภท) ที่ประกาศทางด้านขวาBreakDankDancer, ElectricBoogieDancerแต่ละแบบฟอร์มสามารถมีลักษณะการทำงานเฉพาะของตัวเองสำหรับการทำงานทั่วไปที่กำหนดไว้ในเมธอดซูเปอร์danceคลาส นั่นคือวิธีการประกาศในซูเปอร์คลาสสามารถนำไปใช้แตกต่างกันในลูกหลานได้ ในกรณีนี้ เรากำลังเผชิญกับวิธีการเอาชนะ และนี่คือสิ่งที่สร้างรูปแบบ (พฤติกรรม) ที่หลากหลาย คุณสามารถดูสิ่งนี้ได้โดยการรันโค้ดวิธีการหลักสำหรับการดำเนินการ: เอาต์พุตของโปรแกรม ฉันชื่อ Anton ฉันอายุ 18 ปี ฉันเต้นเหมือนคนอื่นๆ ฉันชื่ออเล็กเซย์ ฉันอายุ 19 ปี ฉันเบรกแดนซ์! ฉันชื่ออิกอร์ ฉันอายุ 20 ปี ฉันเต้นบูกี้ไฟฟ้า! หากเราไม่ใช้การแทนที่ในการสืบทอด เราก็จะไม่ได้รับพฤติกรรมที่แตกต่างกัน BreakDankDancerตัวอย่างเช่น หาก เราElectricBoogieDancerแสดงความคิดเห็นเกี่ยวกับวิธีการสำหรับชั้นเรียนของเราdanceผลลัพธ์ของโปรแกรมจะเป็นดังนี้: ฉันชื่อแอนตัน ฉันอายุ 18 ปี ฉันเต้นเหมือนคนอื่นๆ ฉันชื่ออเล็กเซย์ ฉันอายุ 19 ปี ฉันเต้นเหมือนคนอื่นๆ ฉันชื่ออิกอร์ ฉันอายุ 20 ปี ฉันเต้นเหมือนคนอื่นๆ และนี่หมายความว่าไม่มีประโยชน์ที่จะสร้างBreakDankDancerคลาสElectricBoogieDancerใหม่ หลักการของ Java polymorphism คืออะไรกันแน่? การใช้อ็อบเจ็กต์ในโปรแกรมโดยไม่ทราบประเภทเฉพาะของมันซ่อนอยู่ที่ไหน? ในตัวอย่างของเรา นี่ คือการเรียกใช้เมธอดd.dance()อ็อบเจ็กต์dประเภท DancerJava polymorphism หมายความว่าโปรแกรมไม่จำเป็นต้องรู้ว่าอ็อบเจ็กต์BreakDankDancerหรือ อ็อบเจ็กต์จะเป็นประเภท ElectricBoogieDancerใด สิ่งสำคัญคือว่ามันเป็นผู้สืบทอดของDancerคลาส และถ้าเราพูดถึงลูกหลานก็ควรสังเกตว่าการสืบทอดใน Java ไม่เพียงextendsแต่ แต่ยังรวมถึงimplements. ตอนนี้เป็นเวลาที่ต้องจำไว้ว่า Java ไม่รองรับการสืบทอดหลายรายการ - แต่ละประเภทสามารถมีพาเรนต์เดียว (ซูเปอร์คลาส) และลูกหลาน (คลาสย่อย) ได้ไม่จำกัดจำนวน ดังนั้นจึงใช้อินเทอร์เฟซเพื่อเพิ่มฟังก์ชันการทำงานหลายอย่างให้กับคลาส อินเทอร์เฟซลดการมีเพศสัมพันธ์ของอ็อบเจ็กต์กับพาเรนต์เมื่อเปรียบเทียบกับการสืบทอดและมีการใช้กันอย่างแพร่หลาย ใน Java อินเทอร์เฟซเป็นประเภทอ้างอิง ดังนั้นโปรแกรมจึงสามารถประกาศประเภทให้เป็นตัวแปรของประเภทอินเทอร์เฟซได้ นี่เป็นเวลาที่ดีที่จะยกตัวอย่าง มาสร้างอินเทอร์เฟซกันเถอะ:
public interface Swim {
    void swim();
}
เพื่อความชัดเจน เรามาลองใช้ออบเจ็กต์ที่แตกต่างและไม่เกี่ยวข้องกันและนำอินเทอร์เฟซไปใช้งาน:
public class Human implements Swim {
    private String name;
    private int age;

    public Human(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public void swim() {
        System.out.println(toString()+"I swim with an inflatable ring.");
    }

    @Override
    public String toString() {
        return "Я " + name + ", to me " + age + " years. ";
    }

}

public class Fish implements Swim{
    private String name;

    public Fish(String name) {
        this.name = name;
    }

    @Override
    public void swim() {
        System.out.println("I'm a fish " + name + ". I swim by moving my fins.");

    }

public class UBoat implements Swim {

    private int speed;

    public UBoat(int speed) {
        this.speed = speed;
    }

    @Override
    public void swim() {
        System.out.println("The submarine is sailing, rotating the propellers, at a speed" + speed + " knots.");
    }
}
วิธีmain:
public class Main {

    public static void main(String[] args) {
        Swim human = new Human("Anton", 6);
        Swim fish = new Fish("whale");
        Swim boat = new UBoat(25);

        List<Swim> swimmers = Arrays.asList(human, fish, boat);
        for (Swim s : swimmers) {
            s.swim();
        }
    }
}
ผลลัพธ์ของการดำเนินการเมธอด polymorphic ที่กำหนดไว้ในอินเทอร์เฟซทำให้เราเห็นความแตกต่างในลักษณะการทำงานของประเภทที่ใช้อินเทอร์เฟซนั้น ประกอบด้วยผลลัพธ์ที่แตกต่างกันของการดำเนินการตามswimวิธี หลังจากศึกษาตัวอย่างของเราแล้ว ผู้สัมภาษณ์อาจถามว่าทำไมเมื่อรันโค้ดจากmain
for (Swim s : swimmers) {
            s.swim();
}
วิธีการที่กำหนดไว้ในคลาสเหล่านี้ถูกเรียกสำหรับอ็อบเจ็กต์ของเราหรือไม่? คุณจะเลือกการใช้งานวิธีการที่ต้องการเมื่อรันโปรแกรมได้อย่างไร? เพื่อตอบคำถามเหล่านี้ เราต้องพูดถึงการเชื่อมโยงล่าช้า (ไดนามิก) โดยการผูกเราหมายถึงการสร้างการเชื่อมต่อระหว่างการเรียกเมธอดและการใช้งานเฉพาะในคลาส โดยพื้นฐานแล้ว รหัสจะกำหนดว่าวิธีใดในสามวิธีที่กำหนดไว้ในคลาสที่จะถูกดำเนินการ Java โดยค่าเริ่มต้นจะใช้การโยงล่าช้า (ที่รันไทม์มากกว่าเวลาคอมไพล์ เช่นเดียวกับกรณีของการเชื่อมโยงก่อน) ซึ่งหมายความว่าเมื่อทำการคอมไพล์โค้ด
for (Swim s : swimmers) {
            s.swim();
}
คอมไพเลอร์ยังไม่ทราบว่าโค้ดนั้นมาจากคลาสใดHumanหรือFishว่าUboatมันจะถูกดำเนินการในรูปแบบswim. สิ่งนี้จะถูกกำหนดเฉพาะเมื่อโปรแกรมถูกดำเนินการด้วยกลไกของการจัดส่งแบบไดนามิก - ตรวจสอบประเภทของวัตถุระหว่างการทำงานของโปรแกรมและเลือกการใช้งานวิธีการที่ต้องการสำหรับประเภทนี้ หากคุณถูกถามว่ามีการนำไปใช้อย่างไร คุณสามารถตอบได้ว่าเมื่อโหลดและเริ่มต้นอ็อบเจ็กต์ JVM จะสร้างตารางในหน่วยความจำ และในตารางจะเชื่อมโยงตัวแปรกับค่าของมัน และอ็อบเจ็กต์กับวิธีการของมัน นอกจากนี้ หากวัตถุได้รับการสืบทอดหรือใช้อินเทอร์เฟซ การตรวจสอบการมีอยู่ของวิธีการแทนที่ในคลาสนั้นก่อน หากมี จะเชื่อมโยงกับประเภทนี้ หากไม่ใช่ จะมีการค้นหาเมธอดที่กำหนดไว้ในคลาสที่สูงกว่าหนึ่งระดับ (ในพาเรนต์) และต่อไปจนถึงรากในลำดับชั้นหลายระดับ เมื่อพูดถึงความหลากหลายใน OOP และการนำไปใช้ในโค้ดโปรแกรม เราทราบว่าเป็นวิธีปฏิบัติที่ดีที่จะใช้คำอธิบายนามธรรมเพื่อกำหนดคลาสพื้นฐานโดยใช้คลาสนามธรรมรวมถึงอินเทอร์เฟซ แนวทางปฏิบัตินี้มีพื้นฐานมาจากการใช้นามธรรม - แยกพฤติกรรมและคุณสมบัติทั่วไปและปิดล้อมไว้ในคลาสนามธรรมหรือแยกเฉพาะพฤติกรรมทั่วไป - ในกรณีนี้เราจะสร้างอินเทอร์เฟซ การสร้างและการออกแบบลำดับชั้นของออบเจ็กต์ตามอินเทอร์เฟซและการสืบทอดคลาสเป็นข้อกำหนดเบื้องต้นสำหรับการบรรลุหลักการของ OOP polymorphism เกี่ยวกับปัญหาของความหลากหลายและนวัตกรรมใน Java เราสามารถพูดถึงได้ว่าเมื่อสร้างคลาสนามธรรมและอินเทอร์เฟซที่เริ่มต้นด้วย Java 8 คุณสามารถเขียนการใช้งานเริ่มต้นของวิธีนามธรรมในคลาสพื้นฐานโดยใช้คำdefaultหลัก ตัวอย่างเช่น:
public interface Swim {
    default void swim() {
        System.out.println("Just floating");
    }
}
บางครั้งพวกเขาอาจถามเกี่ยวกับข้อกำหนดในการประกาศวิธีการในคลาสพื้นฐานเพื่อไม่ให้ละเมิดหลักการของความหลากหลาย ทุกอย่างเป็นเรื่องง่ายที่นี่: วิธีการเหล่านี้ไม่ควรเป็นแบบคงที่ส่วนตัวและขั้นสุดท้าย Privateทำให้เมธอดนี้ใช้ได้เฉพาะในคลาสเท่านั้น และคุณไม่สามารถแทนที่เมธอดนั้นในคลาสสืบทอดได้ Staticทำให้เมธอดเป็นคุณสมบัติของคลาส ไม่ใช่อ็อบเจ็กต์ ดังนั้นเมธอด superclass จะถูกเรียกเสมอ สุดท้ายจะทำให้วิธีการไม่เปลี่ยนรูปและซ่อนเร้นจากทายาท

Polymorphism ให้อะไรเราใน Java?

คำถามที่ว่าการใช้ polymorphism ช่วยให้เราทำอะไรได้บ้างก็มักจะเกิดขึ้นเช่นกัน ที่นี่คุณสามารถตอบสั้น ๆ โดยไม่ต้องเจาะลึกเข้าไปในวัชพืชมากเกินไป:
  1. อนุญาตให้คุณแทนที่การใช้งานออบเจ็กต์ นี่คือสิ่งที่การทดสอบเป็นไปตาม
  2. ให้ความสามารถในการขยายโปรแกรม - การสร้างรากฐานสำหรับอนาคตจะง่ายขึ้นมาก การเพิ่มประเภทใหม่ตามประเภทที่มีอยู่เป็นวิธีที่ใช้กันทั่วไปในการขยายฟังก์ชันการทำงานของโปรแกรมที่เขียนในรูปแบบ OOP
  3. ช่วยให้คุณสามารถรวมอ็อบเจ็กต์ที่มีประเภทหรือลักษณะการทำงานทั่วไปเข้าไว้ในคอลเลกชันหรืออาเรย์เดียว และจัดการวัตถุเหล่านั้นให้เหมือนกัน (ดังตัวอย่างของเรา ทำให้ทุกคนเต้น - วิธีการdanceหรือ การว่ายน้ำ - วิธีการswim)
  4. ความยืดหยุ่นในการสร้างประเภทใหม่: คุณสามารถเลือกที่จะใช้วิธีการจากผู้ปกครองหรือแทนที่วิธีการนั้นในลูก

คำพรากจากกันสำหรับการเดินทาง

หลักการของความหลากหลายเป็นหัวข้อที่สำคัญและกว้างมาก ครอบคลุมเกือบครึ่งหนึ่งของOOP ของ Javaและส่วนที่ดีของพื้นฐานของภาษา คุณจะไม่สามารถหลีกเลี่ยงการกำหนดหลักการนี้ในการสัมภาษณ์ได้ ความไม่รู้หรือความเข้าใจผิดมักจะทำให้การสัมภาษณ์สิ้นสุดลง ดังนั้นอย่าขี้เกียจที่จะตรวจสอบความรู้ของคุณก่อนการทดสอบและรีเฟรชหากจำเป็น
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION