Menu
CoddyTech

Lớp bên trong, lớp lồng nhau và lớp ẩn danh

Thuộc phần Lập trình hướng đối tượng trong hành trình Java của Coddy. Bài học 49 trên 87.

Java cho phép bạn định nghĩa lớp bên trong các lớp khác. Những lớp bên trong này giúp tổ chức code bằng cách nhóm các chức năng liên quan lại với nhau và có thể truy cập trực tiếp vào các thành viên của lớp bên ngoài.

Lớp lồng bên trong được định nghĩa là thành viên của một lớp khác. Lớp này có quyền truy cập vào tất cả các trường và phương thức của lớp bên ngoài, kể cả các trường và phương thức riêng tư:

class Outer {
    private String message = "Hello";
    
    class Inner {
        void display() {
            System.out.println(message);  // Có thể truy cập trường private
        }
    }
}

// Cách sử dụng
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display();  // In ra: Hello

Lớp bên trong cục bộ được định nghĩa bên trong một phương thức. Lớp này chỉ có thể được dùng trong phương thức đó và có thể truy cập các biến cục bộ về cơ bản là hằng số:

void process() {
    String prefix = "Result: ";
    
    class LocalHelper {
        void print(int value) {
            System.out.println(prefix + value);
        }
    }
    
    new LocalHelper().print(42);
}

Lớp bên trong ẩn danh là lớp không có tên, được tạo và khởi tạo trong một biểu thức. Lớp này thường được dùng để triển khai giao diện hoặc mở rộng lớp ngay tại chỗ:

Comparator<String> comp = new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.length() - b.length();
    }
};

Lớp bên trong đặc biệt hữu ích khi một lớp chỉ liên quan đến một lớp khác, giúp bạn sắp xếp code gọn gàng và đóng gói.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống giỏ hàng minh họa cả ba loại lớp bên trong. Bạn sẽ tạo một ShoppingCart dùng lớp bên trong lồng nhau để biểu diễn các mặt hàng, lớp bên trong cục bộ để tính mức giảm giá và lớp bên trong ẩn danh để định dạng hóa đơn cuối cùng.

Bạn sẽ sắp xếp code trong ba tệp:

  • ShoppingCart.java: Tạo lớp bên ngoài quản lý trải nghiệm mua sắm. ShoppingCart cần có một trường riêng tư customerName (String).

    Bên trong ShoppingCart, hãy định nghĩa một lớp bên trong lồng nhau tên là Item với hai trường riêng tư: name (String) và price (double). Tạo hàm khởi tạo cho Item để khởi tạo cả hai trường và một phương thức getDetails() trả về: [name]: $[price]

    ShoppingCart cần có một hàm khởi tạo nhận tên khách hàng và một phương thức tên là checkout() nhận một Item cùng phần trăm giảm giá (double). Bên trong checkout():

    1. Tạo một lớp bên trong cục bộ tên là DiscountCalculator với phương thức applyDiscount(double originalPrice) trả về giá sau khi áp dụng phần trăm giảm giá.
    2. Dùng lớp cục bộ để tính giá cuối cùng.
    3. Tạo một lớp bên trong ẩn danh triển khai giao diện Formatter (bạn sẽ định nghĩa giao diện này) để định dạng hóa đơn. Lớp ẩn danh cần ghi đè phương thức format(), trả về một chuỗi hóa đơn gồm nhiều dòng.

    Phương thức checkout() cần trả về chuỗi hóa đơn đã định dạng theo chính xác định dạng sau:

    --- Receipt ---
    Customer: [customerName]
    Item: [item details from getDetails()]
    Discount: [discount]%
    Final Price: $[calculated price]
  • Formatter.java: Định nghĩa một giao diện đơn giản với một phương thức duy nhất: String format(). Lớp bên trong ẩn danh của bạn sẽ triển khai giao diện này bên trong phương thức checkout.
  • Main.java: Hãy bắt đầu trải nghiệm mua sắm! Bạn sẽ nhận ba đầu vào: tên khách hàng (String), tên mặt hàng (String) và giá mặt hàng (double). Phần trăm giảm giá cố định là 10.0.

    Tạo một ShoppingCart với tên khách hàng. Sau đó tạo một Item bằng cú pháp tham chiếu đến lớp bên ngoài: cart.new Item(name, price). Gọi checkout() với mặt hàng và mức giảm giá, rồi in ra hóa đơn được trả về.

Bạn sẽ nhận ba đầu vào theo thứ tự: tên khách hàng, tên mặt hàng và giá mặt hàng.

Ví dụ, nếu các đầu vào là Alice, Laptop và 1000.0, giá cuối cùng sau khi giảm 10% sẽ là 900.0.

Hãy để ý mỗi loại lớp bên trong có một mục đích khác nhau: lớp bên trong lồng nhau nhóm dữ liệu liên quan với lớp bên ngoài, lớp bên trong cục bộ đóng gói logic chỉ cần dùng trong một phương thức, còn lớp bên trong ẩn danh cung cấp cách triển khai giao diện nhanh chóng, chỉ dùng một lần!

Tự làm thử

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Đọc các đầu vào
        String customerName = scanner.nextLine();
        String itemName = scanner.nextLine();
        double itemPrice = scanner.nextDouble();
        
        double discount = 10.0;
        
        // TODO: Tạo ShoppingCart với tên khách hàng
        
        // TODO: Tạo Item bằng: cart.new Item(itemName, itemPrice)
        
        // TODO: Gọi checkout() với mặt hàng và mức giảm giá, rồi in ra kết quả
        
    }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch Java online