Menu
CoddyTech

内部类、嵌套类和匿名类

本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 49 课,共 87 课。

Java 允许你在其他类中定义类。这些内部类可以将相关功能组合在一起,帮助整理代码,并且可以直接访问外部类的成员。

嵌套内部类定义为另一个类的成员。它可以访问外部类的所有字段和方法,包括私有字段和方法:

class Outer {
    private String message = "Hello";
    
    class Inner {
        void display() {
            System.out.println(message);  // 可以访问私有字段
        }
    }
}

// 用法
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display();  // 输出:Hello

局部内部类定义在方法内部。它只能在该方法内使用,并且可以访问实际上为 final 的局部变量:

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

匿名内部类是一个没有名称的类,在一个表达式中创建并实例化。它通常用于即时实现接口或扩展类:

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

当一个类只与另一个类有关时,内部类尤其有用,可以让代码更整洁、更封装。

challenge icon

挑战

简单

我们来构建一个购物车系统,展示三种内部类。你将创建一个 ShoppingCart,使用嵌套内部类表示商品,使用局部内部类计算折扣,并使用匿名内部类格式化最终收据。

你需要将代码分成两个文件:

  • ShoppingCart.java:创建一个管理购物体验的外部类。你的 ShoppingCart 应有一个私有字段 customerName(String)。

    在 ShoppingCart 内部,定义一个名为 Item 的嵌套内部类,其中包含两个私有字段:name(String)和 price(double)。为 Item 添加一个构造函数,用于初始化这两个字段;再添加一个 getDetails() 方法,返回:[name]: $[price]

    你的 ShoppingCart 需要一个接收顾客姓名的构造函数,以及一个名为 checkout() 的方法,该方法接收一个 Item 和一个折扣百分比(double)。在 checkout() 内部:

    1. 创建一个名为 DiscountCalculator 的局部内部类,其中包含一个 applyDiscount(double originalPrice) 方法,返回应用折扣百分比后的价格。
    2. 使用这个局部类计算最终价格。
    3. 创建一个实现 Formatter 接口的匿名内部类(你将定义此接口),用于格式化收据。匿名类应重写 format() 方法,并返回一个多行收据字符串。

    checkout() 方法应返回格式如下的收据字符串:

    --- Receipt ---
    Customer: [customerName]
    Item: [item details from getDetails()]
    Discount: [discount]%
    Final Price: $[calculated price]
  • Formatter.java:定义一个只有一个方法的简单接口:String format()。你的匿名内部类将在 checkout 方法中实现此接口。
  • Main.java:让你的购物车运转起来!你会收到三个输入:顾客姓名(String)、商品名称(String)和商品价格(double)。折扣百分比固定为 10.0。

    使用顾客姓名创建一个 ShoppingCart。然后使用外部类引用语法创建一个 Item:cart.new Item(name, price)。使用该商品和折扣调用 checkout(),并打印返回的收据。

你会依次收到三个输入:顾客姓名、商品名称和商品价格。

例如,如果输入是 Alice、Laptop 和 1000.0,那么打 10% 折扣后的最终价格将是 900.0。

请注意,每种内部类都有不同的用途:嵌套类将相关数据与外部类组合在一起,局部类封装仅在一个方法中需要的逻辑,而匿名类则可以快速实现一次接口!

亲手试试

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取输入
        String customerName = scanner.nextLine();
        String itemName = scanner.nextLine();
        double itemPrice = scanner.nextDouble();
        
        double discount = 10.0;
        
        // TODO: 用客户姓名创建一个 ShoppingCart
        
        // TODO: 使用 cart.new Item(itemName, itemPrice) 创建一个 Item
        
        // TODO: 将商品和折扣传给 checkout(),然后打印结果
        
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Java 在线编译器