说明:以下习题围绕今日授课核心内容——继承(extends) 展开,涵盖继承的概念、格式、多层继承以及继承与构造方法/对象数组/排序的综合应用。
题目分为两部分:随堂练习(继承入门,4 题)和 进阶练习(综合挑战,2 题)。
以下练习围绕继承的基础概念和用法,每题独立可练。
难度:⭐
知识点:继承的格式、子类调用父类方法
创建一个简单的车辆继承体系:
Vehicle 类(父类):
start() —— 输出 "车辆启动"stop() —— 输出 "车辆停止"Car 类(子类,继承 Vehicle):
honk() —— 输出 "汽车鸣笛:滴滴!"Bike 类(子类,继承 Vehicle):
ringBell() —— 输出 "自行车铃铛:叮铃铃!"测试类要求:
Car 对象,调用 start()、honk()、stop() 方法Bike 对象,调用 start()、ringBell()、stop() 方法预期输出:
车辆启动
汽车鸣笛:滴滴!
车辆停止
车辆启动
自行车铃铛:叮铃铃!
车辆停止
难度:⭐⭐
知识点:多层继承、方法追加
创建一个三层继承体系:
Person 类(父类):
name(姓名)、age(年龄)Person(String name, int age)showInfo() —— 输出 "姓名:xxx,年龄:xxx"Student 类(继承 Person):
school(学校,String)Student(String name, int age, String school)
super(name, age) 调用父类构造方法showInfo() —— 输出 "姓名:xxx,年龄:xxx,学校:xxx"Postgraduate 类(继承 Student):
mentor(导师,String)Postgraduate(String name, int age, String school, String mentor)
super(name, age, school) 调用父类构造方法showInfo() —— 输出 "姓名:xxx,年龄:xxx,学校:xxx,导师:xxx"测试类要求:
Person 对象,调用 showInfo()Student 对象,调用 showInfo()Postgraduate 对象,调用 showInfo()示例输出:
姓名:张三,年龄:30
姓名:李四,年龄:22,学校:清华大学
姓名:王五,年龄:25,学校:北京大学,导师:陈教授
提示:子类构造方法中使用
super(参数)调用父类构造方法,必须写在构造方法的第一行。
难度:⭐⭐
知识点:继承 + 构造方法 + 方法重写(Override)
创建动物继承体系:
Animal 类(父类):
name(名字)、age(年龄)Animal(String name, int age)makeSound() —— 输出 "动物发出声音"Dog 类(继承 Animal):
breed(品种,String)Dog(String name, int age, String breed)
super(name, age) 调用父类构造方法makeSound() —— 输出 "狗叫:汪汪汪!"guard() —— 输出 "狗狗在看家护院"Cat 类(继承 Animal):
color(颜色,String)Cat(String name, int age, String color)
super(name, age) 调用父类构造方法makeSound() —— 输出 "猫叫:喵喵喵!"scratch() —— 输出 "猫咪在抓沙发"测试类要求:
Dog 对象(如:"旺财", 3, "金毛"),调用 makeSound() 和 guard()Cat 对象(如:"咪咪", 2, "橘色"),调用 makeSound() 和 scratch()makeSound(),在不同的子类中有不同的行为——这就是 方法重写(Override)示例输出:
狗叫:汪汪汪!
狗狗在看家护院
猫叫:喵喵喵!
猫咪在抓沙发
难度:⭐⭐
知识点:is...a 关系判断、继承设计合理性
根据以下描述,设计合理的类继承体系:
场景:某公司有以下几类人员:
要求:
参考答案思路:
Employee(工号、姓名、基本工资)
├── Manager(岗位津贴)
├── Programmer(项目奖金)
└── Designer(设计提成)
TempWorker(工号、姓名、时薪、工时)—— 不适合继承 Employee,因为没有基本工资
思考:如果让 TempWorker 继承 Employee,会出现什么问题?
以下为综合挑战题,融合继承与构造方法、对象数组、排序、方法重写等知识点。
综合运用继承、构造方法、对象数组、冒泡排序、方法重写、多态等知识点。
某公司需要对员工进行统一的薪资管理。不同类型的员工计算薪资的方式不同:
| 员工类型 | 薪资计算方式 |
|---|---|
| 普通员工 (Employee) | baseSalary(基本工资) |
| 经理 (Manager) | baseSalary + bonus(基本工资 + 岗位津贴) |
| 程序员 (Programmer) | baseSalary + projectBonus(基本工资 + 项目奖金) |
| 设计师 (Designer) | baseSalary + commission(基本工资 + 设计提成) |
Employee 类(父类):
id(工号,int)、name(姓名,String)、baseSalary(基本工资,double)Employee(int id, String name, double baseSalary)getSalary() —— 返回 baseSalary(普通员工就是基本工资)showInfo() —— 输出 "工号:xxx,姓名:xxx,薪资:xxx"Manager 类(继承 Employee):
bonus(岗位津贴,double)Manager(int id, String name, double baseSalary, double bonus)getSalary() —— 返回 baseSalary + bonusshowInfo() —— 输出 "工号:xxx,姓名:xxx,职位:经理,薪资:xxx"Programmer 类(继承 Employee):
projectBonus(项目奖金,double)Programmer(int id, String name, double baseSalary, double projectBonus)getSalary() —— 返回 baseSalary + projectBonusshowInfo() —— 输出 "工号:xxx,姓名:xxx,职位:程序员,薪资:xxx"Designer 类(继承 Employee):
commission(设计提成,double)Designer(int id, String name, double baseSalary, double commission)getSalary() —— 返回 baseSalary + commissionshowInfo() —— 输出 "工号:xxx,姓名:xxx,职位:设计师,薪资:xxx"SalarySystemTest 类:
Employee[] 数组,包含至少 5 个员工(包含 Manager、Programmer、Designer 等各种类型)示例数据:
Employee e1 = new Manager(1001, "张经理", 15000, 5000);
Employee e2 = new Programmer(2001, "李编程", 12000, 3000);
Employee e3 = new Designer(3001, "王设计", 10000, 4000);
Employee e4 = new Employee(4001, "赵普通", 8000);
Employee e5 = new Programmer(2002, "刘代码", 11000, 2500);
遍历输出所有员工信息:调用每个元素的 showInfo() 方法
思考:数组类型是
Employee[],但里面的对象实际上是Manager、Programmer等,为什么调用showInfo()时能正确输出子类的信息?—— 这就是 多态 的体现。
按薪资从高到低排序:使用冒泡排序,按 getSalary() 的返回值降序排列
注意:排序时比较的是
getSalary()的返回值,不同类型的员工计算方式不同,但通过方法重写,同一个方法名在不同子类中有不同的计算逻辑。
排序后再次输出所有员工信息
查找薪资最高的员工:遍历数组,找到并输出薪资最高的员工信息
| 知识点 | 说明 |
|---|---|
| 继承 | Employee 作为父类,Manager/Programmer/Designer 作为子类 |
| 构造方法 + super() | 子类构造方法中调用 super(id, name, baseSalary) |
| 方法重写(Override) | getSalary() 和 showInfo() 在子类中重写 |
| 多态 | 父类引用指向子类对象,调用重写方法时执行子类版本 |
| 对象数组 | Employee[] 存储不同类型的员工对象 |
| 冒泡排序 | 按 getSalary() 返回值降序排序 |
| 遍历查找 | 查找薪资最高的员工 |
========== 排序前 ==========
工号:1001,姓名:张经理,职位:经理,薪资:20000.0
工号:2001,姓名:李编程,职位:程序员,薪资:15000.0
工号:3001,姓名:王设计,职位:设计师,薪资:14000.0
工号:4001,姓名:赵普通,职位:员工,薪资:8000.0
工号:2002,姓名:刘代码,职位:程序员,薪资:13500.0
========== 排序后(按薪资降序) ==========
工号:1001,姓名:张经理,职位:经理,薪资:20000.0
工号:2001,姓名:李编程,职位:程序员,薪资:15000.0
工号:3001,姓名:王设计,职位:设计师,薪资:14000.0
工号:2002,姓名:刘代码,职位:程序员,薪资:13500.0
工号:4001,姓名:赵普通,职位:员工,薪资:8000.0
========== 最高薪资员工 ==========
工号:1001,姓名:张经理,职位:经理,薪资:20000.0
注意:本题引入了 抽象方法 和 接口 的思想,但不需要使用
abstract或interface关键字。通过父类定义统一方法名,子类各自实现自己的版本,体会「约定优于实现」的设计思想。
开发一个图形面积计算器,可以计算不同形状的面积,并支持按面积排序。
Shape 类(父类):
color(颜色,String)Shape(String color)getArea() —— 暂时返回 0.0(作为默认实现,子类会重写)showInfo() —— 输出 "颜色:xxx,面积:xxx",其中面积通过调用 getArea() 获得Circle 类(继承 Shape):
radius(半径,double)Circle(String color, double radius)getArea() —— 返回 π × r²(π 取 3.1415926)radius > 0,否则提示 "半径必须大于0"Rectangle 类(继承 Shape):
width(宽度,double)、height(高度,double)Rectangle(String color, double width, double height)getArea() —— 返回 width × heightwidth > 0 且 height > 0Triangle 类(继承 Shape):
base(底边,double)、height(高,double)Triangle(String color, double base, double height)getArea() —— 返回 base × height / 2base > 0 且 height > 0ShapeCalculatorTest 类:
Shape[] 数组,包含至少 5 个不同的图形对象示例数据:
Shape s1 = new Circle("红色", 5.0); // 面积 ≈ 78.54
Shape s2 = new Rectangle("蓝色", 4.0, 6.0); // 面积 = 24.0
Shape s3 = new Triangle("绿色", 3.0, 4.0); // 面积 = 6.0
Shape s4 = new Circle("黄色", 3.0); // 面积 ≈ 28.27
Shape s5 = new Rectangle("紫色", 8.0, 2.0); // 面积 = 16.0
遍历输出所有图形信息:调用每个元素的 showInfo() 方法
按面积从大到小排序:使用冒泡排序,按 getArea() 返回值降序排列
排序后再次输出所有图形信息
查找面积最大的图形:遍历数组,输出面积最大的图形信息
Square(正方形)类,它应该继承哪个类?需要重写哪些方法?Shape 的 getArea() 返回 0.0 有什么问题?如果用 abstract 关键字强制子类重写会怎样?Shape[] 却能存储 Circle、Rectangle 等不同类型的对象?这体现了 OOP 的哪个特征?========== 排序前 ==========
颜色:红色,面积:78.54
颜色:蓝色,面积:24.0
颜色:绿色,面积:6.0
颜色:黄色,面积:28.27
颜色:紫色,面积:16.0
========== 排序后(按面积降序) ==========
颜色:红色,面积:78.54
颜色:黄色,面积:28.27
颜色:蓝色,面积:24.0
颜色:紫色,面积:16.0
颜色:绿色,面积:6.0
========== 面积最大的图形 ==========
颜色:红色,面积:78.54
提示:
- 本题所有类的构造方法中都需要调用
super(color)来初始化父类的属性- 排序时使用冒泡排序,比较的是
getArea()的返回值- 面积计算使用
double类型,输出时保留两位小数即可(System.out.printf("%.2f", area))- 本题引入了「多态」的思想——相同的
Shape[]数组,存储不同的子类对象,调用相同的方法名getArea(),但执行不同的计算逻辑。
| 序号 | 所属部分 | 核心知识点 | 难度 |
|---|---|---|---|
| 练习 1 | 随堂 | 继承格式、子类调用父类方法 | ⭐ |
| 练习 2 | 随堂 | 多层继承、super() 调用父类构造方法、方法重写 | ⭐⭐ |
| 练习 3 | 随堂 | 继承 + 构造方法 + 方法重写 | ⭐⭐ |
| 练习 4 | 随堂 | is...a 关系判断、继承设计合理性 | ⭐⭐ |
| 进阶 1 | 进阶 | 继承 + 构造方法 + super() + 方法重写 + 多态 + 对象数组 + 冒泡排序 | ⭐⭐⭐⭐ |
| 进阶 2 | 进阶 | 继承 + 构造方法 + 方法重写 + 多态 + 对象数组 + 冒泡排序 + 抽象思想 | ⭐⭐⭐⭐⭐ |