JavaRush /จาวาบล็อก /Random-TH /คลาส ประเภทของคลาสที่ซ้อนกันพร้อมตัวอย่าง
Ярослав
ระดับ
Днепр

คลาส ประเภทของคลาสที่ซ้อนกันพร้อมตัวอย่าง

เผยแพร่ในกลุ่ม
สวัสดีทุกคน. ในหัวข้อนี้ ฉันต้องการพูดโดยละเอียดเกี่ยวกับคลาส Java และประเภทของคลาสเหล่านั้น เพื่อช่วยให้ผู้เริ่มต้นเข้าใจหัวข้อนี้ และบางทีผู้ที่ไม่ใช่มือใหม่อาจเรียนรู้สิ่งใหม่ หากเป็นไปได้ ทุกอย่างจะแสดงโดยใช้ตัวอย่างในชีวิตจริงพร้อมตัวอย่างโค้ดประกอบ มาเริ่มกันเลย. คลาสประเภทของคลาสที่ซ้อนกันพร้อมตัวอย่าง - 1และฉันต้องการทราบว่าสิ่งสำคัญคือการเข้าใจคลาสสองประเภทแรกและคลาสท้องถิ่นและไม่ระบุชื่อเป็นเพียงประเภทย่อยของคลาสภายใน

ชั้นเรียนคืออะไร?

คลาสคือคำอธิบายเชิงตรรกะของบางสิ่ง ซึ่งเป็นเทมเพลตที่คุณสามารถสร้างอินสแตนซ์ที่แท้จริงของสิ่งนั้นได้ กล่าวอีกนัยหนึ่ง มันเป็นเพียงคำอธิบายว่าเอนทิตีที่สร้างขึ้นควรเป็นอย่างไร: คุณสมบัติและวิธีการที่พวกเขาควรมี คุณสมบัติเป็นคุณลักษณะของเอนทิตีวิธีการคือการกระทำที่สามารถทำได้ ตัวอย่างที่ดีของคลาสจากชีวิตจริง ซึ่งช่วยให้เข้าใจว่าคลาสคืออะไร ถือได้ว่าเป็นภาพวาด: ภาพวาดใช้เพื่ออธิบายโครงสร้าง (หนังสติ๊ก, ไขควง) แต่ภาพวาดไม่ใช่การออกแบบ เช่นเดียวกับที่วิศวกรใช้พิมพ์เขียวเพื่อสร้างการออกแบบ การเขียนโปรแกรมใช้คลาสเพื่อสร้างวัตถุที่อธิบายคุณสมบัติและวิธีการ
public class Student {
    private String name, group, specialty;

    public Student(String name, String group, String specialty) {
       this.name = name;
       this.group = group;
       this.specialty = specialty;
   }

   // getters/setters
}
ในตัวอย่างนี้ เราสร้างคลาส Java ที่อธิบายเอนทิตี "นักเรียน": นักเรียนแต่ละคนมีชื่อ กลุ่ม และความเชี่ยวชาญพิเศษ ตอนนี้ ที่อื่นๆ ในโปรแกรม เราสามารถสร้างตัวอย่างที่แท้จริงของคลาสนี้ได้ กล่าวอีกนัยหนึ่ง: ถ้าชั้นเรียนStudentเป็นภาพที่นักเรียนควรจะเป็นอย่างไร ตัวอย่างที่สร้างขึ้นก็คือตัวนักเรียนจริงๆ ตัวอย่างการสร้างนักเรียนใหม่: new Student("Ivan", "KI-17-2", "Computer Engineering");ตัวดำเนินการnewค้นหาชั้นเรียนStudentแล้วเรียกเมธอดพิเศษ (ตัวสร้าง) ของคลาสนี้ ตัวสร้างส่งคืนวัตถุคลาสสำเร็จรูปStudent- นักเรียนที่รักและหิวโหยของเราโดยไม่มีทุน :))

ประเภทของคลาสใน Java

ใน Java มีคลาสอยู่ 4 ประเภทภายในคลาสอื่น:
  1. คลาสภายในที่ซ้อนกันเป็นคลาสที่ไม่คงที่ภายในคลาสภายนอก

  2. คลาสสแตติกที่ซ้อนกันเป็นคลาสสแตติกภายในคลาสภายนอก

  3. คลาสท้องถิ่น Javaเป็นคลาสภายในวิธีการ

  4. คลาส Java ที่ไม่ระบุชื่อเป็นคลาสที่สร้างขึ้นทันที

เราจะพูดถึงแต่ละเรื่องแยกกัน

คลาสที่ไม่คงที่ภายในคลาสภายนอก

ก่อนอื่น ฉันอยากให้คุณเข้าใจว่าสิ่งนี้คืออะไรพร้อมตัวอย่างจริง เพราะมันทำให้เข้าใจได้ง่ายขึ้นมาก ตอนนี้เราจะแยกย่อยสิ่งที่ยิ่งใหญ่จริงๆ ออกเป็นส่วนประกอบเล็กๆ และเราจะแยกชิ้นส่วนเครื่องบิน! อย่างไรก็ตาม เพื่อเป็นตัวอย่าง ก็เพียงพอที่จะแสดงให้เห็นเพียงเล็กน้อย เราจะไม่แยกย่อยให้หมด เพื่อให้เห็นภาพกระบวนการนี้ เราจะใช้แผนภาพเครื่องบิน คลาสประเภทของคลาสที่ซ้อนกันพร้อมตัวอย่าง - 2 ขั้นแรก เราต้องสร้างคลาสAirplaneที่เราสามารถเพิ่มคำอธิบายเล็กๆ น้อยๆ ได้: ชื่อเครื่องบิน รหัสประจำตัว เที่ยวบิน
public class Airplane {
    private String name, id, flight;

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    // getters/setters
}
ตอนนี้เราต้องการเพิ่มปีก สร้างคลาสแยกกันเหรอ? บางทีนี่อาจเป็นตรรกะถ้าเรามีโปรแกรมที่ซับซ้อนสำหรับการออกแบบเครื่องบินและที่ที่เราจำเป็นต้องสร้างคลาสที่ได้รับมาจำนวนมาก (คลาสที่มีตรรกะเหมือนกับคลาสพาเรนต์นั่นคือคลาสที่สืบทอดมา แต่ ดังนั้นพวกเขาจึงขยายคลาสพาเรนต์โดยการเพิ่มตรรกะหรือคุณลักษณะที่มีรายละเอียดมากขึ้น) แต่จะเกิดอะไรขึ้นถ้าเรามีเกมที่มีเครื่องบินเพียงลำเดียว? จากนั้นจะมีเหตุผลมากขึ้นสำหรับเราที่จะทำโครงสร้างทั้งหมดให้เสร็จสิ้นในที่เดียว (ในคลาสเดียว) นี่คือจุดที่คลาสที่ซ้อนกันแบบไม่คงที่เข้ามามีบทบาท โดยพื้นฐานแล้ว นี่เป็นคำอธิบายโดยละเอียดเพิ่มเติมเกี่ยวกับรายละเอียดบางส่วนของคลาสภายนอกของเรา ในตัวอย่างนี้ เราต้องสร้างปีกสำหรับเครื่องบินทั้งซ้ายและขวา มาสร้างกันเถอะ!
public class Airplane {
    private String name, id, flight;
    private Wing leftWing = new Wing("Red", "X3"), rightWing = new Wing("Blue", "X3");

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    private class Wing {
        private String color, model;

        private Wing(String color, String model) {
            this.color = color;
            this.model = model;
        }

        // getters/setters
    }

    // getters/setters
}
ดังนั้นเราจึงสร้างคลาส (ปีก) ที่ไม่คงที่WingภายในคลาสAirplane(เครื่องบิน) และเพิ่มตัวแปรสองตัว - ปีกซ้ายและปีกขวา และแต่ละปีกก็มีคุณสมบัติของตัวเอง (สี, รุ่น) ที่เราสามารถเปลี่ยนได้ วิธีนี้ทำให้คุณสามารถจัดวางโครงสร้างได้มากเท่าที่คุณต้องการ และหมายเหตุ: ก่อนหน้านี้บนแผนภาพมีชิ้นส่วนของเครื่องบินค่อนข้างมาก และในความเป็นจริง เราสามารถแบ่งชิ้นส่วนทั้งหมดออกเป็นคลาสภายในได้ แต่กระบวนการดังกล่าวไม่แนะนำให้เลือกเสมอไป จำเป็นต้องติดตามช่วงเวลาดังกล่าวขึ้นอยู่กับงาน คุณอาจไม่จำเป็นต้องใช้ปีกเลยในการแก้ปัญหา จากนั้นก็ไม่จำเป็นต้องทำ มันเหมือนกับการตัดคนเป็นขา แขน ลำตัว และศีรษะ เป็นไปได้ แต่ทำไมถ้าคลาสนี้ใช้เพื่อเก็บข้อมูลเกี่ยวกับผู้คนเท่านั้น คุณลักษณะของคลาส Java ที่ซ้อนกันแบบไม่คงที่:
  1. พวกมันมีอยู่ในวัตถุเท่านั้น ดังนั้นเพื่อสร้างพวกมันคุณต้องมีวัตถุ กล่าวอีกนัยหนึ่ง: เราออกแบบปีกของเราให้เป็นส่วนหนึ่งของเครื่องบิน ดังนั้นเพื่อสร้างปีกเราจำเป็นต้องมีเครื่องบิน ไม่เช่นนั้นเราก็ไม่ต้องการมัน
  2. ไม่สามารถมีตัวแปรคงที่ภายในคลาส Java หากคุณต้องการค่าคงที่หรือค่าคงที่ คุณจะต้องย้ายพวกมันไปยังคลาสภายนอก นี่เป็นเพราะการเชื่อมต่อที่ใกล้ชิดของคลาสที่ซ้อนกันแบบไม่คงที่กับคลาสภายนอก
  3. คลาสมีสิทธิ์เข้าถึงฟิลด์ส่วนตัวทั้งหมดของคลาสภายนอกได้อย่างเต็มที่ คุณลักษณะนี้ทำงานได้สองวิธี
  4. คุณสามารถรับการอ้างอิงถึงอินสแตนซ์ของคลาสภายนอกได้ ตัวอย่าง: เครื่องบิน นี่คือลิงก์ไปยังเครื่องบิน นี่คือลิงก์ไปยังปีก

คลาสแบบคงที่ภายในคลาสภายนอก

คลาสประเภทนี้ไม่แตกต่างจากคลาสภายนอกทั่วไป ยกเว้นสิ่งหนึ่ง: เพื่อสร้างอินสแตนซ์ของคลาสดังกล่าว คุณจะต้องแสดงรายการเส้นทางทั้งหมดจากคลาสภายนอกไปยังคลาสที่ต้องการ โดยคั่นด้วยจุด ตัวอย่างเช่น: Building.Plaftorm platform = new Building.Platform(); คลาสแบบคงที่ใช้เพื่อวางคลาสที่เกี่ยวข้องไว้เคียงข้างกัน เพื่อให้โครงสร้างเชิงตรรกะทำงานได้ง่ายขึ้น ตัวอย่างเช่น: เราสามารถสร้างคลาสภายนอกBuildingโดยที่จะมีรายการคลาสเฉพาะที่จะแสดงถึงสิ่งปลูกสร้างเฉพาะ
public abstract class Building {
    private String name, address, type;

    Building(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public static class Platform extends Building {
        public Platform(String name, String address) {
            super(name, address);
            setType("Platform");
        }

        // some additional logic
    }

    public static class House extends Building {
        public House(String name, String address) {
            super(name, address);
            setType("House");
        }

        // some additional logic
    }

    public static class Shop extends Building {
        public Shop(String name, String address) {
            super(name, address);
            setType("Shop");
        }

        // some additional logic
    }

    // getters/setters
}
ตัวอย่างนี้แสดงให้เห็นว่าคลาสแบบสแตติกช่วยให้คุณสามารถจัดทำโครงสร้างเชิงตรรกะในรูปแบบที่สะดวกยิ่งขึ้นได้อย่างไร หากไม่มีอยู่ เราจะต้องสร้าง 4 คลาสที่แตกต่างกันโดยสิ้นเชิง ข้อดีของแนวทางนี้:
  1. จำนวนชั้นเรียนลดลง
  2. ชั้นเรียนทั้งหมดอยู่ภายในชั้นเรียนหลัก เราสามารถติดตามลำดับชั้นทั้งหมดได้โดยไม่ต้องเปิดแต่ละคลาสแยกกัน
  3. เราสามารถอ้างถึงคลาส Building และ IDE จะแจ้งรายการคลาสย่อยทั้งหมดของคลาสนี้แล้ว ซึ่งจะทำให้ค้นหาชั้นเรียนที่คุณต้องการได้ง่ายขึ้นและแสดงภาพรวมแบบองค์รวมมากขึ้น
ตัวอย่างของการสร้างอินสแตนซ์ของคลาสสแตติกที่ซ้อนกัน:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); ฉันอยากจะทราบด้วยว่ากลยุทธ์นี้ใช้ในคลาส AWT 2D เพื่ออธิบายรูปร่าง เช่น Line2D, Arc2D, Ellipse2D และอื่นๆ

ชั้นเรียนในท้องถิ่น

คลาสเหล่านี้ถูกประกาศภายในวิธีอื่น ในความเป็นจริง พวกเขามีคุณสมบัติทั้งหมดของคลาสที่ซ้อนกันแบบไม่คงที่ มีเพียงคุณเท่านั้นที่สามารถสร้างอินสแตนซ์ของพวกเขาในเมธอดเท่านั้น และวิธีการนั้นไม่สามารถคงที่ได้ (ในการสร้างคลาสเหล่านั้น คุณต้องมีอินสแตนซ์ของคลาสภายนอก การอ้างอิงถึง อินสแตนซ์ของออบเจ็กต์ที่เรียกจะถูกส่งผ่านไปยังวิธีที่ไม่คงที่โดยปริยาย และในวิธีคงที่จะไม่มีวิธีการสำหรับลิงก์นี้) แต่พวกเขามีลักษณะเฉพาะของตัวเอง:
  1. คลาสท้องถิ่นสามารถทำงานได้กับตัวแปรเมธอดสุดท้ายเท่านั้น ประเด็นก็คืออินสแตนซ์ของคลาสโลคัลสามารถเก็บไว้ในฮีปได้หลังจากที่เมธอดเสร็จสิ้น และสามารถลบตัวแปรได้ หากตัวแปรถูกประกาศเป็นขั้นสุดท้าย คอมไพลเลอร์สามารถบันทึกสำเนาของตัวแปรเพื่อใช้ในภายหลังโดยอ็อบเจ็กต์ได้ และอีกอย่างหนึ่ง: เนื่องจาก Java เวอร์ชัน 8+ ขึ้นไป คุณสามารถใช้ตัวแปรที่ไม่ใช่ตัวแปรสุดท้ายในคลาสโลคัลได้ แต่จะมีเงื่อนไขว่าจะไม่เปลี่ยนแปลง
  2. ไม่สามารถประกาศคลาสท้องถิ่นด้วยตัวดัดแปลงการเข้าถึง
  3. คลาสท้องถิ่นสามารถเข้าถึงตัวแปรเมธอดได้
คลาสท้องถิ่นสามารถพบได้น้อยมากเนื่องจากทำให้โค้ดอ่านยากและไม่มีข้อดีใด ๆ ยกเว้นการเข้าถึงตัวแปรเมธอดเพียงประการเดียว ฉันไม่รู้ว่าตัวอย่างใดของชั้นเรียนในท้องถิ่นที่สามารถแสดงให้เห็นการใช้งานที่มีประสิทธิภาพ ดังนั้นฉันจะแสดงตัวอย่างของฉันเท่านั้น สมมติว่าเรามีคลาสPerson(จะถือว่านี่คือบุคคล) ที่มีคุณสมบัติstreet(ถนน) house(บ้าน) เราต้องการคืนวัตถุบางอย่างเพื่อเข้าถึงเฉพาะตำแหน่งของบุคคลนั้น ในการดำเนินการนี้ เราได้สร้างอินเทอร์เฟซ AddressContainer ซึ่งหมายถึงการจัดเก็บข้อมูลเกี่ยวกับตำแหน่งของบุคคล
public class Person {
    private String name, street, house;

    public Person(String name, String street, String house) {
        this.name = name;
        this.street = street;
        this.house = house;
    }

    private interface AddressContainer {
        String getStreet();
        String getHouse();
    }

    public AddressContainer getAddressContainer() {
        class PersonAddressContainer implements AddressContainer {
            final String street = Person.this.street, house = Person.this.house;

            @Override
            public String getStreet() {
                return this.street;
            }

            @Override
            public String getHouse() {
                return this.house;
            }
        }

        return new PersonAddressContainer();
    }

    public static void main(String[] args) {
        Person person = new Person("Nikita", "Sholohova", "17");

        AddressContainer address = person.getAddressContainer();

        System.out.println("Address: street - " + address.getStreet() + ", house - " + address.getHouse());
    }

    // getters/setters
}
อย่างที่คุณเห็น ภายในวิธีการที่เราสร้างคลาสที่ใช้การจัดเก็บตำแหน่งของบุคคล สร้างตัวแปรคงที่ที่นั่น (เพื่อที่ว่าหลังจากออกจากวิธีการแล้ว ตัวแปรจะถูกเก็บไว้ในวัตถุ) และใช้วิธีในการรับที่อยู่และ บ้าน. ตอนนี้เราสามารถใช้วัตถุนี้ในตำแหน่งอื่นในโปรแกรมเพื่อรับตำแหน่งของบุคคลได้ ฉันเข้าใจว่าตัวอย่างนี้ไม่เหมาะและมันจะถูกต้องมากกว่าหากทำเพียงแค่ปล่อย getters ไว้ในคลาสPersonอย่างไรก็ตาม มีการแสดงการสร้างคลาสนี้และการใช้งานที่เป็นไปได้ และจากนั้นก็ขึ้นอยู่กับคุณ

ชั้นเรียนที่ไม่ระบุชื่อ

ภายใต้ประทุน คลาสที่ไม่ระบุตัวตนเป็นเพียงคลาสที่ซ้อนกันแบบไม่คงที่ทั่วไป ลักษณะเฉพาะของพวกเขาคือใช้งานง่าย คุณสามารถเขียนชั้นเรียนของคุณได้โดยตรงเมื่อสร้างอินสแตนซ์ของชั้นเรียนอื่น
public class Animal {
    public void meow() {
        System.out.println("Meow!");
    }

    public static void main(String[] args) {
        Animal anonTiger = new Animal() {
            @Override
            public void meow() {
                System.out.println("Raaar!");
            }
        };

        Animal notAnonTiger = new Animal().new Tiger();

        anonTiger.meow(); // будет выведено Raaar!
        notAnonTiger.meow(); // будет выведено Raaar!
    }

    private class Tiger extends Animal {
        @Override
        public void meow() {
            System.out.println("Raaar!");
        }
    }
}
โดยพื้นฐานแล้ว เราเพียงแค่รวมสองสิ่งไว้ในที่เดียว: การสร้างอินสแตนซ์ของคลาสเดียว ( Animal) และการสร้างอินสแตนซ์ของคลาสภายในที่สืบทอด ( Tiger) มิฉะนั้น เราจำเป็นต้องสร้างคลาสแยกกัน และใช้โครงสร้างที่ยาวกว่าเพื่อให้ได้ผลลัพธ์เดียวกัน การใช้คลาสที่ไม่เปิดเผยตัวตนเป็นสิ่งที่สมเหตุสมผลในหลายกรณี โดยเฉพาะอย่างยิ่งเมื่อ:
  • เนื้อหาของชั้นเรียนสั้นมาก
  • จำเป็นต้องมีอินสแตนซ์เดียวของคลาสเท่านั้น
  • คลาสถูกใช้ ณ สถานที่ที่สร้างขึ้นหรือหลังจากนั้นทันที
  • ชื่อคลาสไม่สำคัญและไม่ทำให้โค้ดเข้าใจง่ายขึ้น
คลาสที่ไม่เปิดเผยตัวตนมักใช้ใน GUI เพื่อสร้างตัวจัดการเหตุการณ์ ตัวอย่างเช่น หากต้องการสร้างปุ่มและตอบสนองต่อการคลิก:
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
อย่างไรก็ตาม หลังจาก Java 8 พวกเขาเริ่มใช้นิพจน์แลมบ์ดา แต่ยังคงมีการเขียนโค้ดจำนวนมากก่อนเวอร์ชัน 8 และคุณอาจพบคำจารึกดังกล่าว (และจะพบระหว่างการฝึกของคุณใน JavaRush)\ อะนาล็อก กับแลมบ์ดา:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
ท้ายบทความ ขอขอบคุณทุกท่านที่ให้ความสนใจและหวังว่าคุณจะได้เรียนรู้สิ่งใหม่ ๆ หรือเข้าใจสิ่งที่คุณไม่เคยเข้าใจมาก่อน ฉันขอชี้แจงด้วยว่าบทความนี้อยู่ใน หมวดหมู่ "ความ ใส่ใจในรายละเอียด" นี่เป็นงานแรกของฉันดังนั้นฉันหวังว่าจะเป็นประโยชน์กับใครบางคน ในอนาคตอันใกล้นี้เมื่อมีไอเดียใหม่ๆ เกิดขึ้น ฉันจะพยายามเขียนอย่างอื่น ฉันมีไอเดียเดียว... ขอให้ทุกคนโชคดีและประสบความสำเร็จในการเขียนโปรแกรม :)
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION