JavaRush /Blog Java /Random-VI /Lớp, kiểu lớp lồng nhau kèm ví dụ
Ярослав
Mức độ
Днепр

Lớp, kiểu lớp lồng nhau kèm ví dụ

Xuất bản trong nhóm
Chào mọi người. Trong chủ đề này, tôi muốn nói chi tiết về các lớp Java và các loại của chúng để giúp những người mới bắt đầu hiểu chủ đề này và có lẽ những người không phải là người mới sẽ học được điều gì đó mới. Nếu có thể, mọi thứ sẽ được hiển thị bằng các ví dụ thực tế kèm theo mã ví dụ. Bắt đầu nào. Lớp, kiểu lớp lồng nhau kèm ví dụ - 1Và tôi muốn lưu ý rằng điều chính là phải hiểu hai loại lớp đầu tiên, và cục bộ và ẩn danh chỉ đơn giản là các kiểu con của lớp bên trong.

Một lớp học là gì?

Lớp là một mô tả logic về một thứ gì đó, một mẫu mà bạn có thể tạo các phiên bản thực tế của chính thứ đó. Nói cách khác, nó chỉ đơn giản là mô tả về các thực thể được tạo sẽ như thế nào: chúng nên có những thuộc tính và phương thức nào. Thuộc tính là đặc điểm của một thực thể, phương thức là những hành động mà nó có thể thực hiện. Một ví dụ điển hình về một lớp trong đời thực, giúp hiểu lớp là gì, có thể được coi là các bản vẽ: các bản vẽ được sử dụng để mô tả các cấu trúc (máy phóng, tuốc nơ vít), nhưng bản vẽ không phải là một thiết kế. Giống như các kỹ sư sử dụng bản thiết kế để tạo ra các thiết kế, lập trình sử dụng các lớp để tạo ra các đối tượng có các thuộc tính và phương thức được mô tả.
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
}
Trong ví dụ này, chúng ta đã tạo một lớp Java mô tả thực thể “student”: mỗi sinh viên có một tên, nhóm và chuyên môn. Bây giờ, ở những nơi khác trong chương trình, chúng ta có thể tạo các ví dụ thực tế về lớp này. Nói cách khác: nếu lớp học Studentlà bức chân dung của một học sinh thì đối tượng được tạo ra chính là học sinh đó. Ví dụ về tạo một sinh viên mới: new Student("Ivan", "KI-17-2", "Computer Engineering");Toán tử newtìm kiếm lớp Studentvà sau đó gọi một phương thức đặc biệt (hàm tạo) của lớp này. Người xây dựng trả về một đối tượng lớp làm sẵn Student- sinh viên thân yêu, đói khát của chúng ta mà không có học bổng :))

Các loại lớp trong Java

Trong Java có 4 loại lớp bên trong một lớp khác:
  1. Các lớp bên trong lồng nhau là các lớp không tĩnh bên trong một lớp bên ngoài.

  2. Các lớp tĩnh lồng nhau là các lớp tĩnh bên trong một lớp bên ngoài.

  3. Các lớp cục bộ Java là các lớp bên trong các phương thức.

  4. Các lớp Java ẩn danh là các lớp được tạo nhanh chóng.

Chúng tôi sẽ nói về từng người trong số họ một cách riêng biệt.

Các lớp không tĩnh bên trong một lớp bên ngoài

Đầu tiên, tôi muốn bạn hiểu đây là gì qua một ví dụ thực tế, vì nó giúp bạn dễ hiểu hơn nhiều. Vì vậy, bây giờ chúng ta sẽ chia một vật thực sự lớn thành các bộ phận nhỏ hơn và chúng ta sẽ tháo rời một chiếc máy bay! Tuy nhiên, để làm ví dụ, chỉ trình bày một chút là đủ, chúng tôi sẽ không chia nhỏ nó hoàn toàn. Để hình dung quá trình này, chúng ta sẽ sử dụng sơ đồ máy bay. Lớp, kiểu lớp lồng nhau kèm ví dụ - 2 Đầu tiên, chúng ta cần tạo một lớp Airplaneđể có thể thêm một chút mô tả: tên máy bay, mã nhận dạng, chuyến bay.
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
}
Bây giờ chúng tôi muốn thêm đôi cánh. Tạo một lớp riêng biệt? Có lẽ đây là logic nếu chúng ta có một chương trình phức tạp để thiết kế máy bay và nơi chúng ta cần tạo ra một số lượng lớn các lớp dẫn xuất (các lớp có cùng logic với lớp cha, tức là lớp mà chúng kế thừa, nhưng vì vậy chúng mở rộng lớp cha bằng cách thêm logic hoặc các đặc điểm chi tiết hơn), nhưng điều gì sẽ xảy ra nếu chúng ta chỉ có một trò chơi mà chúng ta có một mặt phẳng? Khi đó sẽ hợp lý hơn nếu chúng ta hoàn thành toàn bộ cấu trúc ở một nơi (trong một lớp). Đây là lúc các lớp lồng nhau không tĩnh phát huy tác dụng. Về cơ bản, đây là mô tả chi tiết hơn về một số chi tiết về lớp bên ngoài của chúng tôi. Trong ví dụ này, chúng ta cần tạo cánh cho một chiếc máy bay - trái và phải. Hãy sáng tạo!
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
}
WingVì vậy, chúng tôi đã tạo một lớp (cánh) lồng nhau không tĩnh bên trong một lớp Airplane(máy bay) và thêm hai biến - cánh trái và cánh phải. Và mỗi cánh đều có thuộc tính riêng (màu sắc, kiểu dáng) mà chúng ta có thể thay đổi. Bằng cách này, bạn có thể bố trí nhân viên cho các cấu trúc theo nhu cầu. Và lưu ý: trước đó trên sơ đồ có khá nhiều bộ phận của máy bay và trên thực tế, chúng ta có thể chia tất cả các bộ phận thành các lớp bên trong, nhưng quy trình như vậy không phải lúc nào cũng được khuyến khích. Những khoảnh khắc như vậy cần phải được theo dõi tùy thuộc vào nhiệm vụ. Bạn có thể không cần đôi cánh nào cả để giải quyết vấn đề. Thế thì không cần phải làm chúng. Nó giống như cắt một người thành chân, tay, thân và đầu - điều đó là có thể, nhưng tại sao lớp này chỉ được sử dụng để lưu trữ dữ liệu về con người? Các tính năng của các lớp Java lồng nhau không tĩnh:
  1. Chúng chỉ tồn tại trong các đối tượng, vì vậy để tạo ra chúng bạn cần có một đối tượng. Nói cách khác: chúng ta đã thiết kế chiếc cánh của mình để trở thành một bộ phận của một chiếc máy bay, vì vậy để tạo ra một chiếc cánh, chúng ta cần một chiếc máy bay, nếu không thì chúng ta không cần nó.
  2. Không thể có các biến tĩnh bên trong một lớp Java. Nếu bạn cần một số hằng số hoặc bất cứ thứ gì tĩnh, bạn cần chuyển chúng sang lớp bên ngoài. Điều này là do sự liên kết chặt chẽ của lớp lồng không tĩnh với lớp bên ngoài.
  3. Lớp có toàn quyền truy cập vào tất cả các trường riêng tư của lớp bên ngoài. Tính năng này hoạt động theo hai cách.
  4. Bạn có thể lấy tham chiếu đến một thể hiện của lớp bên ngoài. Ví dụ: Máy bay. Đây là liên kết đến một chiếc máy bay, đây là liên kết đến một chiếc cánh.

Các lớp tĩnh bên trong một lớp bên ngoài

Loại lớp này không khác gì lớp ngoài thông thường, ngoại trừ một điều: để tạo một thể hiện của lớp như vậy, bạn cần liệt kê toàn bộ đường dẫn từ lớp ngoài đến lớp mong muốn, cách nhau bằng dấu chấm. Ví dụ: Building.Plaftorm platform = new Building.Platform(); Các lớp tĩnh được sử dụng để đặt các lớp liên quan cạnh nhau để cấu trúc logic dễ làm việc hơn. Ví dụ: chúng ta có thể tạo một lớp bên ngoài Building, trong đó sẽ có một danh sách các lớp cụ thể đại diện cho một tòa nhà cụ thể.
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
}
Ví dụ này chứng tỏ các lớp tĩnh cho phép bạn đóng gói một cấu trúc logic thành một dạng thuận tiện hơn như thế nào. Nếu chúng không tồn tại, chúng ta sẽ cần tạo 4 lớp hoàn toàn khác nhau. Ưu điểm của phương pháp này:
  1. Số lượng lớp học đã giảm.
  2. Tất cả các lớp đều nằm trong lớp cha của chúng. Chúng tôi có thể theo dõi toàn bộ hệ thống phân cấp mà không cần mở từng lớp riêng biệt.
  3. Chúng ta có thể tham khảo lớp Xây dựng và IDE sẽ nhắc toàn bộ danh sách tất cả các lớp con của lớp này. Điều này sẽ giúp bạn dễ dàng tìm thấy các lớp bạn cần và hiển thị toàn bộ bức tranh một cách tổng thể hơn.
Một ví dụ về việc tạo một phiên bản của lớp tĩnh lồng nhau:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); Tôi cũng muốn lưu ý rằng chiến lược này được sử dụng trong các lớp AWT 2D để mô tả các hình dạng, chẳng hạn như Line2D, Arc2D, Ellipse2D và các lớp khác.

Các lớp học địa phương

Các lớp này được khai báo bên trong các phương thức khác. Trên thực tế, chúng có tất cả các thuộc tính của một lớp lồng không tĩnh, chỉ có bạn mới có thể tạo các thể hiện của chúng chỉ trong một phương thức và phương thức đó không thể tĩnh (để tạo chúng, bạn cần một thể hiện của một lớp bên ngoài, một tham chiếu đến một lớp bên ngoài). thể hiện của đối tượng gọi được truyền ngầm sang các phương thức không tĩnh và trong phương thức tĩnh không có phương thức nào cho liên kết này). Nhưng chúng có những đặc điểm riêng:
  1. Các lớp cục bộ chỉ có thể hoạt động với các biến phương thức cuối cùng. Vấn đề là các phiên bản của lớp cục bộ có thể được lưu trữ trong heap sau khi phương thức hoàn thành và biến có thể bị xóa. Nếu biến được khai báo là cuối cùng thì trình biên dịch có thể lưu một bản sao của biến để đối tượng sử dụng sau này. Và một điều nữa: vì có hơn 8 phiên bản Java, bạn có thể sử dụng các biến không phải cuối cùng trong các lớp cục bộ, nhưng chỉ với điều kiện là chúng sẽ không thay đổi.
  2. Các lớp cục bộ không thể được khai báo bằng các công cụ sửa đổi truy cập.
  3. Các lớp cục bộ có quyền truy cập vào các biến phương thức.
Các lớp cục bộ có thể cực kỳ hiếm được tìm thấy, vì chúng làm cho mã khó đọc và không có bất kỳ lợi thế nào, ngoại trừ một - quyền truy cập vào các biến phương thức. Tôi không biết có thể lấy ví dụ nào về lớp địa phương để cho thấy cách sử dụng hiệu quả của chúng, vì vậy tôi sẽ chỉ đưa ra ví dụ của mình. Giả sử chúng ta có một lớp Person(giả sử đây là một người) có thuộc tính street(đường phố), house(nhà). Chúng tôi muốn trả lại một số đối tượng để chỉ truy cập vào vị trí của người đó. Để thực hiện điều này, chúng tôi đã tạo giao diện addressContainer, giao diện này ngụ ý lưu trữ dữ liệu về vị trí của một người.
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
}
Như bạn có thể thấy, bên trong phương thức, chúng ta đã tạo một lớp thực hiện việc lưu trữ vị trí của một người, tạo các biến không đổi ở đó (để sau khi thoát khỏi phương thức, các biến được lưu trữ trong một đối tượng) và triển khai một phương thức để lấy địa chỉ và căn nhà. Bây giờ chúng ta có thể sử dụng đối tượng này ở những nơi khác trong chương trình để lấy vị trí của một người. Tôi hiểu rằng ví dụ này không lý tưởng và sẽ đúng hơn nếu thực hiện nó đơn giản bằng cách để các getters trong lớp Person, tuy nhiên, việc tạo lớp này và khả năng sử dụng của nó đã được hiển thị, sau đó tùy thuộc vào bạn.

Lớp ẩn danh

Về cơ bản, các lớp ẩn danh chỉ là các lớp lồng nhau không tĩnh thông thường. Điểm đặc biệt của họ là dễ sử dụng. Bạn có thể viết trực tiếp lớp của mình khi tạo một thể hiện của lớp khác.
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!");
        }
    }
}
Về bản chất, chúng ta chỉ cần kết hợp hai thứ vào một nơi: tạo một thể hiện của một lớp ( Animal) và tạo một thể hiện của lớp bên trong kế thừa của nó ( Tiger). Mặt khác, chúng ta cần tạo lớp riêng biệt và sử dụng các cấu trúc dài hơn để đạt được kết quả tương tự. Việc sử dụng các lớp ẩn danh là hợp lý trong nhiều trường hợp, đặc biệt khi:
  • thân lớp rất ngắn;
  • chỉ cần một thể hiện của lớp;
  • lớp được sử dụng tại nơi nó được tạo hoặc ngay sau nó;
  • Tên lớp không quan trọng và không làm cho mã dễ hiểu hơn.
Các lớp ẩn danh thường được sử dụng trong GUI để tạo trình xử lý sự kiện. Ví dụ: để tạo một nút và phản ứng với lần nhấp vào nút đó:
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
Tuy nhiên, sau Java 8, họ bắt đầu sử dụng biểu thức lambda, nhưng vẫn còn rất nhiều mã được viết trước phiên bản 8 và bạn có thể gặp (và sẽ gặp trong quá trình đào tạo về JavaRush) những dòng chữ như vậy.\ Tương tự với lambdas:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
Cuối bài Cảm ơn tất cả các bạn đã quan tâm và tôi hy vọng rằng bạn đã học được điều gì đó mới hoặc hiểu được điều gì đó mà trước đây bạn chưa hiểu. Tôi cũng muốn làm rõ rằng bài viết này thuộc thể loại “chú ý đến chi tiết” . Đây là tác phẩm đầu tiên của tôi, vì vậy tôi hy vọng nó có ích cho ai đó. Sắp tới khi có ý tưởng mới mình sẽ cố gắng viết cái gì khác, mình chỉ có một ý tưởng thôi... Chúc mọi người may mắn và thành công trong lập trình :)
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION