20260727-内部类练习.md 13 KB

2026-07-27 内部类(Inner Class)进阶练习(课堂练习用)

说明:今日习题围绕 内部类(Inner Class) 深入展开,重点覆盖 静态成员内部类局部内部类,并综合巩固成员内部类、私有内部类的设计原则。共 3 道练习,难度递进。


练习 1:静态成员内部类——电脑硬件升级(显卡与硬盘)⭐⭐

知识点:静态成员内部类、static 修饰内部类的特点、静态内部类的创建格式、静态内部类与外部类的关系

需求说明

在之前的练习中,我们使用 普通成员内部类 设计了计算机的 CPU 和内存。这次,我们换成 静态成员内部类 来设计电脑的 显卡(GraphicsCard)硬盘(HardDisk),体验静态内部类在创建方式和访问权限上的不同。

显卡和硬盘同样是计算机的重要部件,但使用 static 修饰后,它们可以不依赖外部类实例而独立创建。

类设计

Computer 类(外部类)

成员 说明
私有属性 brand(品牌,String)、price(价格,double)
构造方法 Computer(String brand, double price)
方法 void showInfo() —— 输出电脑品牌和价格
方法 void startComputer() —— 输出启动信息,调用显卡的 render() 和硬盘的 readData()

GraphicsCard 类(静态成员内部类

成员 说明
私有属性 model(型号,String)、vram(显存,int,单位 GB)
构造方法 GraphicsCard(String model, int vram)
方法 void render() —— 输出 "显卡(xxx,xxx GB)正在渲染画面..."
方法 void showSpec() —— 输出 "显卡规格:xxx,显存:xxx GB"

HardDisk 类(静态成员内部类

成员 说明
私有属性 capacity(容量,int,单位 GB)、type(类型,String,如 "SSD" / "HDD")
构造方法 HardDisk(int capacity, String type)
方法 void readData() —— 输出 "硬盘(xxx GB,xxx)正在读取数据..."
方法 void writeData() —— 输出 "硬盘(xxx GB,xxx)正在写入数据..."

测试类要求

TestComputer2

  1. 直接创建显卡对象

    Computer.GraphicsCard gpu = new Computer.GraphicsCard("RTX 4070", 12);
    

    静态内部类 不需要 先创建外部类对象,格式为 外部类名.内部类名

  2. 直接创建硬盘对象

    Computer.HardDisk disk = new Computer.HardDisk(1024, "SSD");
    
  3. 调用显卡的 showSpec()render() 方法

  4. 调用硬盘的 readData()writeData() 方法

  5. 创建 Computer 对象("华硕", 8999.0),调用 startComputer()

  6. 尝试:在 GraphicsCard 的 render() 方法中直接访问外部类的 brand 属性——观察是否编译报错

思考题

  1. 静态内部类和普通成员内部类在 创建方式 上有什么区别?从 new 的语法角度分析。

  2. 静态内部类能否直接访问外部类的 实例成员(如 brandprice)?为什么?

  3. 如果确实需要在静态内部类中访问外部类的实例成员,应该如何改造代码?(提示:通过参数传递外部类引用)

  4. 对比之前的 CPU(成员内部类)和现在的 GraphicsCard(静态内部类),哪种内部类更适合描述"计算机的部件"这个场景?说说你的理由。

预期输出

========== 独立创建显卡 ==========
显卡规格:RTX 4070,显存:12 GB
显卡(RTX 4070,12 GB)正在渲染画面...

========== 独立创建硬盘 ==========
硬盘(1024 GB,SSD)正在读取数据...
硬盘(1024 GB,SSD)正在写入数据...

========== 启动计算机 ==========
计算机 华硕 正在启动...
显卡(RTX 4070,12 GB)正在渲染画面...
硬盘(1024 GB,SSD)正在读取数据...

练习 2:局部内部类——网上购物车结算系统 ⭐⭐

知识点:局部内部类、局部内部类的作用域、局部内部类访问方法参数和局部变量、effectively final

需求说明

在电商购物车结算时,我们需要计算商品的总价、折扣价等。计算逻辑只在该次结算方法中使用,不需要对外暴露,因此非常适合设计为 局部内部类

类设计

ShoppingCart 类(外部类)

成员 说明
私有属性 items(商品名称数组,String[]
私有属性 prices(单价数组,double[]
私有属性 quantities(数量数组,int[]
构造方法 ShoppingCart(String[] items, double[] prices, int[] quantities) —— 三个数组长度应一致
方法 void checkout(double discountRate) —— 结算方法,内部定义局部内部类 完成计算
方法 void showCart() —— 显示购物车中的所有商品信息

checkout 方法中的局部内部类 OrderCalculator

checkout(double discountRate) 方法内部定义以下局部内部类:

成员 说明
构造方法 OrderCalculator() —— 可输出 "订单计算器已创建"
方法 double calculateTotal() —— 遍历商品,计算 单价 × 数量 的总和
方法 double calculateDiscountedTotal(double rate) —— 调用 calculateTotal() 后乘以折扣率
方法 void printReceipt() —— 逐行打印每个商品的名称、单价、数量、小计,最后打印总价和折后价

测试类要求

TestShoppingCart

  1. 准备测试数据:

    String[] items = {"笔记本", "钢笔",  "橡皮"};
    double[] prices = {15.5,    5.0,    2.0};
    int[] quantities = {2,       3,      5};
    
  2. 创建 ShoppingCart 对象,调用 showCart() 显示购物车

  3. 调用 checkout(0.8) 传入 8 折折扣,观察输出

  4. 验证局部内部类的封装性:尝试在 main 方法中直接创建 OrderCalculator 对象:

    // 这行应编译报错 —— OrderCalculator 是局部内部类,仅在 checkout 方法内可见
    // OrderCalculator calculator = new OrderCalculator();  // ❌
    

思考题

  1. 局部内部类的作用域是什么?它可以在哪些位置被访问?

  2. OrderCalculator 中访问了 checkout 方法的参数 discountRate。从 Java 8 开始,这个参数有什么要求?(提示:effectively final)

  3. 如果将 OrderCalculator 改成成员内部类,设计上是否合理?为什么?

  4. 局部内部类除了可以访问外部类的成员,还能访问什么?

预期输出

========== 购物车信息 ==========
商品清单:
  笔记本   ¥15.5  × 2  = ¥31.0
  钢笔     ¥5.0   × 3  = ¥15.0
  橡皮     ¥2.0   × 5  = ¥10.0

========== 开始结算(折扣率:0.8)==========
订单计算器已创建
---------- 购物清单 ----------
笔记本   ¥15.5  × 2  = ¥31.0
钢笔     ¥5.0   × 3  = ¥15.0
橡皮     ¥2.0   × 5  = ¥10.0
-------------------------------
商品总价:¥56.0
折扣后价:¥44.8

练习 3:综合练习——学校管理系统(成员内部类 + 静态内部类 + 局部内部类)⭐⭐⭐

知识点:私有成员内部类、静态成员内部类、局部内部类综合运用、内部类的设计原则

需求说明

设计一个 学校管理系统,要求使用不同类型的内部类来组织代码:

  • 学生(Student) 是学校的核心成员,应设计为 私有成员内部类,只能通过学校对象创建
  • 教师信息(TeacherInfo) 是学校的公共信息,应设计为 静态成员内部类,可独立访问
  • 上课点名(AttendanceRecorder) 仅在 holdClass() 方法中使用,应设计为 局部内部类

类设计

School 类(外部类)

成员 说明
私有属性 schoolName(学校名称,String)
私有属性 address(地址,String)
构造方法 School(String schoolName, String address)
方法 void showInfo() —— 输出学校信息
方法 Student createStudent(String name, int age, String studentId) —— 创建并返回学生对象(因为 Student 是私有的,外界无法直接 new)
方法 void holdClass(TeacherInfo teacher, String course) —— 上课方法,内部使用 局部内部类 记录出勤
方法 static void showSchoolRule() —— 输出学校校训(静态方法)

Student 类(私有成员内部类

成员 说明
私有属性 name(姓名,String)、age(年龄,int)、studentId(学号,String)
构造方法 Student(String name, int age, String studentId)
方法 void study() —— 输出 "学生 xxx(学号:xxx)正在学习..."
方法 void showInfo() —— 输出学生完整信息

TeacherInfo 类(静态成员内部类

成员 说明
私有属性 name(姓名,String)、subject(教授科目,String)、salary(工资,double)
构造方法 TeacherInfo(String name, String subject, double salary)
方法 void teach() —— 输出 "教师 xxx 正在教授 xxx..."
方法 void showInfo() —— 输出教师信息(含学校名称——思考能否直接访问?)
静态方法 static void showTeacherRule() —— 输出 "为人师表,教书育人"

holdClass 方法中的局部内部类 AttendanceRecorder

成员 说明
私有属性 attendedStudents(出勤学生名单,String[]),通过构造方法传入
构造方法 AttendanceRecorder(String[] attendedStudents)
方法 void record() —— 遍历出勤名单,逐行输出 "✅ xxx 已签到"
方法 void showSummary() —— 输出出勤总人数

测试类要求

TestSchool

  1. 创建 School 对象("清华附中", "北京市海淀区")

  2. 通过 School 创建学生——Student 是私有内部类,不能直接 new

    // Student s = new Student("张三", 18, "2024001");    // ❌ 编译报错——Student 是私有的
    // ❌ 也无法通过 School.Student 方式创建,因为 private 限制
    
    // ✅ 必须通过 School 的公共方法创建
    // 假设 School 中有 createStudent 方法
    
  3. 直接创建教师对象——TeacherInfo 是静态内部类,且非私有:

    School.TeacherInfo teacher = new School.TeacherInfo("李老师", "数学", 8000.0);
    teacher.teach();
    teacher.showInfo();
    
  4. 调用 holdClass() 方法上课,传入教师对象和课程名称

  5. 调用 School.showSchoolRule()School.TeacherInfo.showTeacherRule() 静态方法

思考题

  1. 在本系统中,Student 被设计为 private 内部类,TeacherInfo 没有使用 private。根据内部类的设计原则,这样设计是否合理?从"外部类对内部类的控制权"角度分析。

  2. TeacherInfo.showInfo() 中,如果想要输出学校名称 schoolName,能否直接访问?如果不能,应该如何改造代码?(提示:静态内部类不能直接访问外部类的实例成员)

  3. AttendanceRecorder 作为局部内部类,它的作用范围是什么?如果在 holdClass 方法外部创建一个 AttendanceRecorder 对象,会发生什么?

  4. 对比练习 1 和练习 3 中的静态内部类,总结静态内部类在什么场景下更适用。

预期输出

========== 学校信息 ==========
清华附中(地址:北京市海淀区)

========== 创建学生 ==========
学生 张三(学号:2024001)正在学习...
学生 李四(学号:2024002)正在学习...

========== 教师信息 ==========
教师 李老师 正在教授 数学...
教师信息:李老师 | 数学 | 工资:8000.0
—— 所属学校:清华附中

========== 开始上课 ==========
教师 李老师 正在教授 数学...
✅ 张三 已签到
✅ 李四 已签到
✅ 王五 已签到
今日出勤人数:3 人

========== 校规校训 ==========
学校校训:自强不息,厚德载物
教师守则:为人师表,教书育人

附:内部类类型对比总结

内部类类型 修饰符 创建格式 能否直接访问外部类实例成员 适用场景
成员内部类 无 / private / public 外部类.new 内部类() ✅ 可以 内部细节需依赖外部类实例(如心脏之于人)
私有成员内部类 private 通过外部类方法返回 ✅ 可以 不想让外界直接访问,完全由外部类控制
静态成员内部类 static new 外部类.内部类() ❌ 不可以(只能访问静态成员) 内部类不依赖外部类实例,可独立使用
局部内部类 非修饰符(方法内定义) 仅在方法内 new ✅ 可以(且可访问方法局部变量) 仅在某方法内使用的临时逻辑