一、本章知识回顾
知识点 说明
继承 子类继承父类的成员变量和方法
方法重写 子类重新定义父类的方法
super关键字 访问父类的成员变量、方法和构造方法
多态 父类引用指向子类对象
final关键字 防止继承、防止重写、定义常量
抽象类 包含抽象方法的类,不能实例化
接口 完全抽象的规范,支持多实现
二、为什么要继承?
2.1 问题引入
假设要设计学生和教师两个类:
学生类:姓名、年龄、学号、学习()
教师类:姓名、年龄、工号、教学()
你会发现,学生和教师都有相同的属性(姓名、年龄)。如果每个类都重复写一遍,代码会非常冗余。
继承的解决方案:把共同的特征提取到“人类”中,让学生和教师继承这个类。
2.2 继承的概念
- 父类(超类):被继承的类
- 子类(派生类):继承父类的类
- 关键字:
extends
// 父类
class Person {
String name;
int age;
void eat() {
System.out.println(name + "正在吃饭");
}
}
// 子类继承父类
class Student extends Person {
String studentId; // 子类特有的属性
void study() { // 子类特有的方法
System.out.println(name + "正在学习");
}
}
AI写代码
java
运行
2.3 继承的好处
| 好处 |
说明 |
| 代码复用 |
子类自动拥有父类的属性和方法 |
| 易于维护 |
修改父类即可影响所有子类 |
| 体现is-a关系 |
Student is a Person(学生是一个人) |
| AI写代码 |
|
| markdown |
|
| 三、子类与父类 |
|
3.1 继承的基本语法
class 子类名 extends 父类名 {
// 子类特有的成员变量
// 子类特有的成员方法
}
AI写代码
java
运行
3.2 继承示例:银行账户
代码解析
/**
父类:银行账户
*/
class BankAccount {
String accountNo; // 账号
double balance; // 余额
// 构造方法
BankAccount(String accountNo, double balance) {
this.accountNo = accountNo;
this.balance = balance;
}
// 存款
void deposit(double amount) {
balance += amount;
System.out.println(“存入 “ + amount + “ 元,余额:” + balance);
}
// 取款
void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
System.out.println(“取出 “ + amount + “ 元,余额:” + balance);
} else {
System.out.println(“余额不足!”);
}
}
void showInfo() {
System.out.println(“账号:” + accountNo + “,余额:” + balance);
}
}
/**
子类:储蓄账户(继承BankAccount)
特点:有利息
*/
class SavingsAccount extends BankAccount {
double interestRate; // 子类特有的属性:利率
SavingsAccount(String accountNo, double balance, double interestRate) {
super(accountNo, balance); // 调用父类构造方法
this.interestRate = interestRate;
}
// 子类特有的方法:计算利息
void addInterest() {
double interest = balance * interestRate;
balance += interest;
System.out.println(“增加利息:” + interest + “ 元,余额:” + balance);
}
}
public class InheritanceDemo {
public static void main(String[] args) {
System.out.println(“=== 普通账户 ===”);
BankAccount acc1 = new BankAccount(“1001”, 1000);
acc1.deposit(500);
acc1.withdraw(200);
System.out.println("\n=== 储蓄账户 ===");
SavingsAccount acc2 = new SavingsAccount("2001", 2000, 0.03);
acc2.deposit(300);
acc2.addInterest();
}
}
AI写代码
java
运行
运行结果
=== 普通账户 ===
存入 500.0 元,余额:1500.0
取出 200.0 元,余额:1300.0
=== 储蓄账户 ===
存入 300.0 元,余额:2300.0
增加利息:69.0 元,余额:2369.0
AI写代码
关键点说明
父类 BankAccount 定义了银行账户的基本属性和方法,包括账号、余额、存款、取款和显示账户信息。
子类 SavingsAccount 继承了 BankAccount,并增加了特有的属性 interestRate 和方法 addInterest(),用于计算并添加利息。
在 main 方法中,分别创建了普通账户和储蓄账户的实例,演示了存款、取款和利息计算的功能。
四、方法重写(Override)
4.1 什么是方法重写?
子类可以重新定义(覆盖)父类中已有的方法,这叫做方法重写。
重写规则:
- 方法名相同
- 参数列表相同
- 返回值类型相同(或是其子类)
- 访问权限不能比父类更严格
4.2 示例:信用卡账户(重写取款方法)
信用卡账户实现代码
/**
子类:信用卡账户(继承BankAccount)
特点:可以透支
*/
class CreditAccount extends BankAccount {
double creditLimit; // 透支额度
CreditAccount(String accountNo, double balance, double creditLimit) {
super(accountNo, balance);
this.creditLimit = creditLimit;
}
// 重写取款方法(支持透支)
@Override
void withdraw(double amount) {
if (balance + creditLimit >= amount) {
balance -= amount;
System.out.println(“取出 “ + amount + “ 元,余额:” + balance);
} else {
System.out.println(“超过透支额度!”);
}
}
}
public class OverrideDemo {
public static void main(String[] args) {
CreditAccount acc = new CreditAccount(“3001”, 0, 5000);
acc.withdraw(2000); // 可以透支
acc.withdraw(4000); // 超出额度
}
}
AI写代码
java
运行
运行结果示例
取出 2000.0 元,余额:-2000.0
超过透支额度!
AI写代码
text
代码说明
信用卡账户类继承自银行账户基类,通过重写取款方法实现透支功能。当取款金额不超过账户余额与透支额度之和时允许交易,否则拒绝交易并提示超额。
构造方法接收账户号、初始余额和透支额度三个参数,初始化时需调用父类构造方法。透支额度作为信用卡账户特有的属性单独存储。
4.3 @Override注解
@Override是可选的,但推荐加上:
- 让编译器 帮忙检查是否正确的重写了父类方法
- 提高代码可读性
4.4 重写 vs 重载
方法重写(Override)与方法重载(Overload)对比
比较项 方法重写(Override) 方法重载(Overload)
发生位置 子类和父类之间 同一个类中
方法名 必须相同 必须相同
参数列表 必须相同 必须不同
返回值 相同或子类(协变返回类型) 无关
访问修饰符 不能比父类更严格(如父类为 protected,子类可为 public,但不能为 private) 无限制
异常抛出 不能抛出比父类更宽泛的检查异常 无限制
作用 实现多态,子类提供特定实现 提供同名方法的不同参数版本
关键区别说明
方法重写(Override)
发生在继承关系中,子类重新定义父类的方法。
方法签名(名称和参数列表)必须完全一致。
返回类型可以是原类型的子类型(协变返回)。
访问权限不能比父类方法更严格。
方法重载(Overload)
发生在同一类中,通过不同参数列表区分同名方法。
返回值类型、访问修饰符和异常声明可自由变化。
仅需参数列表不同(类型、顺序或数量)。
示例代码
方法重写示例
class Parent {
protected void show() {
System.out.println(“Parent’s show”);
}
}
class Child extends Parent {
@Override
public void show() { // 访问修饰符更宽松,参数列表相同
System.out.println(“Child’s show”);
}
}
AI写代码
java
运行
方法重载示例
class Calculator {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) { // 参数类型不同
return a + b;
}
int add(int a, int b, int c) { // 参数数量不同
return a + b + c;
}
}
AI写代码
java
运行
五、super关键字
5.1 super的作用
super用于在子类中访问父类的成员。
表格转换结果
用法 说明
super.成员变量 访问父类成员变量
super.成员方法() 调用父类成员方法
super(参数) 调用父类构造方法(必须在第一行)
注意事项
表格已按照原始内容格式转换,保持清晰对齐
每列内容准确对应原始数据
表格边框采用标准Markdown表格语法
列宽根据内容自动调整
5.2 示例:电脑
代码解析
/**
父类:电脑
*/
class Computer {
String cpu;
int ram;
Computer(String cpu, int ram) {
this.cpu = cpu;
this.ram = ram;
}
void showSpec() {
System.out.println(“CPU:” + cpu + “,内存:” + ram + “GB”);
}
}
/**
子类:游戏电脑
*/
class GamingComputer extends Computer {
String gpu; // 显卡
GamingComputer(String cpu, int ram, String gpu) {
super(cpu, ram); // 调用父类构造方法
this.gpu = gpu;
}
@Override
void showSpec() {
super.showSpec(); // 调用父类的方法
System.out.println(“显卡:” + gpu);
}
}
public class SuperDemo {
public static void main(String[] args) {
GamingComputer gc = new GamingComputer(“i7-13700K”, 32, “RTX 4080”);
gc.showSpec();
}
}
AI写代码
java
运行
运行结果
CPU:i7-13700K,内存:32GB
显卡:RTX 4080
AI写代码
关键点说明
super关键字用于在子类中访问父类的成员变量或方法。在构造方法中,super()用于调用父类的构造方法,必须放在子类构造方法的第一行。
方法重写时,使用super.方法名()可以调用父类被重写的方法,实现功能的扩展而非完全覆盖。
继承关系中,子类可以继承父类的非私有成员,同时可以添加自己的特有成员,形成更具体的类。
5.3 注意事项
子类构造方法必须先调用父类构造方法
class Parent {
Parent(String name) { // 有参构造
System.out.println(“Parent: “ + name);
}
}
// 正确写法
class Child extends Parent {
Child(String name) {
super(name); // 必须手动调用父类有参构造
}
}
AI写代码
java
运行
六、多态
6.1 什么是多态?
多态:同一个方法调用,作用于不同的对象,产生不同的行为。
实现多态的三个条件:
- 有继承关系
- 子类重写父类的方法
- 父类引用指向子类对象6.2 多态示例
/*** 父类:动物*/
class Animal {
void sound() {
System.out.println(“动物发出声音”);
}
}
/*** 子类:狗*/
class Dog extends Animal {
@Override
void sound() {
System.out.println(“狗:汪汪汪!”);
}
}
/*** 子类:猫*/
class Cat extends Animal {
@Override
void sound() {
System.out.println(“猫:喵喵喵!”);
}
}
public class PolymorphismDemo {
public static void main(String[] args) {
// 多态:父类引用指向子类对象
Animal animal1 = new Dog();
Animal animal2 = new Cat();
// 同一个方法调用,产生不同行为
animal1.sound(); // 狗:汪汪汪!
animal2.sound(); // 猫:喵喵喵!
// 多态的方便之处:用一个数组存放多种动物
Animal[] animals = {new Dog(), new Cat(), new Dog()};
for (Animal animal : animals) {
animal.sound(); // 不需要知道具体是哪种动物
}
}
}
AI写代码
java
运行
6.3 对象类型转换
// 向上转型(自动,安全)
Animal animal = new Dog();
// 向下转型(强制,有风险)
Dog dog = (Dog) animal;
// instanceof 判断类型(避免转型异常)
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
AI写代码
java
运行
七、final关键字
7.1 final的三种用法
修饰符作用示例表
修饰符 作用 示例
final 类 不能被继承 final class String
final 方法 不能被重写 public final void print()
final 变量 只能赋值一次(常量) final double PI = 3.14
7.2 示例
// 1. final变量:常量
class Constants {
final double PI = 3.14159; // 声明时初始化
void test() {
// PI = 3.14; // 编译错误:不能修改
}
}
// 2. final方法:子类不能重写
class Parent {
final void finalMethod() {
System.out.println(“这个方法不能被重写”);
}
}
// 3. final类:不能有子类
final class FinalClass {
// 类体
}
// class SubClass extends FinalClass {} // 编译错误
AI写代码
java
运行
八、抽象类
8.1 什么是抽象类?
当一个父类只知道子类应该有什么方法,但不知道如何实现时,使用抽象类。
- 用
abstract 关键字修饰
- 抽象方法没有方法体
- 抽象类不能实例化(不能 new)
8.2 示例:图形面积计算
/**
抽象类:图形
*/
abstract class Shape {
String color;
Shape(String color) {
this.color = color;
}
// 抽象方法:只有声明,没有实现
abstract double getArea();
abstract double getPerimeter();
// 普通方法(可以被子类继承)
void showColor() {
System.out.println(“颜色:” + color);
}
}
/**
子类:圆形
*/
class Circle extends Shape {
double radius;
Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
double getArea() {
return Math.PI * radius * radius;
}
@Override
double getPerimeter() {
return 2 * Math.PI * radius;
}
}
/**
子类:矩形
*/
class Rectangle extends Shape {
double width;
double height;
Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
double getArea() {
return width * height;
}
@Override
double getPerimeter() {
return 2 * (width + height);
}
}
public class AbstractDemo {
public static void main(String[] args) {
// Shape shape = new Shape(“红色”); // 错误:抽象类不能实例化
Shape circle = new Circle("红色", 5);
Shape rectangle = new Rectangle("蓝色", 4, 6);
System.out.println("=== 圆形 ===");
circle.showColor();
System.out.println("面积:" + circle.getArea());
System.out.println("周长:" + circle.getPerimeter());
System.out.println("\n=== 矩形 ===");
rectangle.showColor();
System.out.println("面积:" + rectangle.getArea());
System.out.println("周长:" + rectangle.getPerimeter());
}
}
AI写代码
java
运行
抽象类要点:
- 含有抽象方法的类必须是抽象类
- 抽象类可以没有抽象方法
- 子类必须实现所有抽象方法,否则子类也是抽象类
九、接口
9.1 什么是接口?
接口是完全抽象的规范,定义了“能做什么”,但不关心“怎么做”。
- 用
interface 关键字定义
- 用
implements 关键字实现
9.2 接口的特性
成员类型与默认修饰符对照表
成员类型 默认修饰符 说明
常量 public static final 接口中定义的变量自动是常量
抽象方法 public abstract 接口中的方法自动是抽象的
9.3 示例:USB接口
代码解析
/**
}
/**
鼠标实现USB接口
*/
class Mouse implements USB {
@Override
public void plugIn() {
System.out.println(“鼠标已插入”);
}
@Override
public void work() {
System.out.println(“鼠标:移动光标、点击”);
}
@Override
public void plugOut() {
System.out.println(“鼠标已拔出”);
}
}
/**
键盘实现USB接口
*/
class Keyboard implements USB {
@Override
public void plugIn() {
System.out.println(“键盘已插入”);
}
@Override
public void work() {
System.out.println(“键盘:输入文字”);
}
@Override
public void plugOut() {
System.out.println(“键盘已拔出”);
}
}
public class InterfaceDemo {
public static void main(String[] args) {
USB mouse = new Mouse();
USB keyboard = new Keyboard();
System.out.println("=== 鼠标 ===");
mouse.plugIn();
mouse.work();
mouse.plugOut();
System.out.println("\n=== 键盘 ===");
keyboard.plugIn();
keyboard.work();
keyboard.plugOut();
System.out.println("\nUSB标准:" + USB.STANDARD);
}
}
AI写代码
java
运行
运行结果
代码执行后的输出结果如下:
=== 鼠标 ===
鼠标已插入
鼠标:移动光标、点击
鼠标已拔出
=== 键盘 ===
键盘已插入
键盘:输入文字
键盘已拔出
USB标准:USB 3.0
AI写代码
关键点说明
接口USB定义了三个抽象方法和一个常量。Mouse和Keyboard类实现了USB接口,并提供了具体的方法实现。
在InterfaceDemo类的main方法中,创建了Mouse和Keyboard的实例,并通过接口类型引用调用各自的方法。最后打印了接口中定义的常量STANDARD。
该示例展示了Java接口的基本特性,包括抽象方法的定义、实现类的编写以及接口常量的使用。
9.4 接口的多实现
一个类可以实现多个接口,这是Java实现多继承的方式。
interface A {
void methodA();
}
interface B {
void methodB();
}
class MultipleImpl implements A, B {
@Override
public void methodA() {
System.out.println(“实现A的方法”);
}
@Override
public void methodB() {
System.out.println(“实现B的方法”);
}
}
AI写代码
java
运行
9.5 接口与抽象类的对比
抽象类与接口对比
比较项 抽象类 接口
关键字 abstract class interface
继承/实现 extends implements
多继承 不支持 支持
成员变量 可以有各种类型 只能是常量
构造方法 有 没有
普通方法 可以有 只有抽象方法(Java 8前)
使用场景 有共同代码的基类 定义规范/能力
注:Java 8及以后版本允许接口包含默认方法(default方法)和静态方法。
十、综合示例:教材“银行与利息”案例
/*** 抽象类:银行账户*/
abstract class BankAccount {
String accountNo;
double balance;
BankAccount(String accountNo, double balance) {
this.accountNo = accountNo;
this.balance = balance;
}
// 抽象方法:计算利息
abstract double calculateInterest();
void showInfo() {
System.out.println("账号:" + accountNo + ",余额:" + balance);
System.out.println("利息:" + calculateInterest());
}
}
/*** 定期账户*/
class FixedAccount extends BankAccount {
double rate; // 利率
FixedAccount(String accountNo, double balance, double rate) {
super(accountNo, balance);
this.rate = rate;
}
@Override
double calculateInterest() {
return balance * rate;
}
}
/*** 活期账户*/
class CurrentAccount extends BankAccount {
double rate;
int days; // 存款天数
CurrentAccount(String accountNo, double balance, double rate, int days) {
super(accountNo, balance);
this.rate = rate;
this.days = days;
}
@Override
double calculateInterest() {
return balance * rate * days / 365;
}
}
public class BankDemo {
public static void main(String[] args) {
BankAccount account1 = new FixedAccount(“1001”, 10000, 0.035);
BankAccount account2 = new CurrentAccount(“2001”, 10000, 0.003, 180);
System.out.println("=== 定期账户 ===");
account1.showInfo();
System.out.println("\n=== 活期账户 ===");
account2.showInfo();
}
}
AI写代码
java
运行
十一、常见错误与注意点
常见Java继承与接口错误对照表
错误写法 正确写法 关键说明
class Child extends Parent1, Parent2 class Child implements Interface1, Interface2 Java单继承限制,类只能继承一个父类,但可实现多个接口
子类构造方法未调用super() 显式调用super(参数) 父类不存在默认构造器时,子类必须显式调用父类构造器
误用@Override注解 保持方法签名完全一致 包括方法名、参数列表、返回类型,否则触发编译错误
抽象类遗漏抽象方法声明 使用abstract修饰无实现的方法 抽象方法必须以分号结尾,不能包含方法体
接口实现类未声明public 显式添加public修饰符 接口方法默认public,但实现类必须显式声明为public
典型问题深度解析
多继承限制 Java通过单继承+多接口实现解决菱形继承问题。当需要复用多个父类功能时,应改用组合模式或接口默认方法。
构造器链规则 子类构造器必须调用父类构造器,若未显式调用且父类无默认构造器,编译器报错。调用语句必须作为构造器首行代码。
注解校验机制 @Override严格校验重写规范,包括协变返回类型等细节。现代IDE通常能实时提示签名不匹配问题。
抽象方法特征 抽象类可以包含具体方法,但抽象方法必须由子类实现。注意与接口方法的区别:抽象方法可受保护,接口方法始终公开。
访问控制一致性 接口方法默认公开且不可降低可见性。实现类若省略public修饰符会导致访问权限收缩,违反里氏替换原则。
十二、小结
本章学习了:
- 继承:子类继承父类,实现代码复用
-方法重写:子类重新定义父类的方法
- super关键字:访问父类的成员
- 多态:父类引用指向子类对象
- final关键字:防止继承、防止重写、定义常量
- 抽象类:包含抽象方法的类,不能实例化
- 接口:完全抽象的规范,支持多实现