1. 引言
- 什么是继承?:
继承是指面向对象编程中实现代码复用的核心机制。它允许开发者基于现有类创建新类(称为派生类),在保留原有类特性的同时进行功能扩展。这种机制不仅体现了面向对象程序设计的层次化结构,也符合从简单到复杂的认知规律。继承的核心价值在于提取共性特征,从而高效实现代码复用。
- 为什么使用继承?:
在项目开发中,多个类经常需要定义相同属性,直接重复定义会导致代码冗余。通过继承机制,不仅能消除重复代码,其层次化结构还能提升代码可读性和可维护性。
在图书馆管理系统中,书籍分类管理是一个典型场景。假设系统需要管理三种类型的书籍:普通书籍、电子书和稀有古籍。如果不使用继承,每类书籍都需要独立定义属性(如书名、作者、ISBN)和方法(如借阅、归还),导致大量重复代码。例如,电子书和稀有古籍都需要重复定义与普通书籍相同的借阅逻辑,仅因存储方式或保护措施不同而略有差异。这种实现方式不仅增加维护成本,在新增书籍类型(如有声书)时还需从头编写所有功能。
简单来说,各类图书虽然形式各异,但都具备一些共性特征。例如,所有图书都包含书名和作者信息,都可以进行借阅和归还。在此基础上,电子书额外具有文件格式和下载链接等属性;古籍则需要特别记录保存温度和修复状态等信息。未来如果要新增有声书类型,只需说明它与其他图书一样具有基本属性,再补充音频时长这一特殊项即可。这种设计既避免了重复定义共性特征,又能清晰体现电子书、古籍等作为"图书"这一基础类型的衍生特性,为系统升级和维护提供了便利。
2. Java继承基础
-
2.1 语法基础:
- 使用关键字extends来实现继承,具体格式如下:
- 修饰符 class (子类)类名 extends (父类)类名{ }
-
Modifier class subclassName extends parentClassName{ // }
- 使用关键字extends来实现继承,具体格式如下:
-
2.2 示例
-
2.2.1 基本示例:
class Vehicle { void start() { System.out.println("Vehicle started"); } } class Car extends Vehicle { // 子类继承父类方法 }上述例子中,Car为子类,继承父类Vehicle.
*此时 Car也叫做 派生类 -
2.2.2 实例:
-
假设现在有一个手机类别,包含Xiaomi手机,Huawei手机,Apple手机,并定义它们的产品特性与功能。我们可以对比使用继承和不使用继承两种实现方式的区别
-
不使用继承
-
-
class ApplePhone{ String model; String cpu; String system; public ApplePhone(String model, String cpu,String system) { this.model = model; this.cpu = cpu; this.system = system; } public void powerOn() { System.out.println(this.model + "正在开机"); } public void powerOff() { System.out.println(this.model + "正在关机"); } public void useSystem() { System.out.println(this.model + " 使用的是 " + this.system); } } class HuaweiPhone{ String model; String cpu; String system; public HuaweiPhone(String model, String cpu,String system) { this.model = model; this.cpu = cpu; this.system = system; } public void powerOn() { System.out.println(this.model + "正在开机"); } public void powerOff() { System.out.println(this.model + "正在关机"); } public void useSystem() { System.out.println(this.model + " 使用的是 " + this.system); } } class XiaomiPhone{ String model; String cpu; String system; public XiaomiPhone(String model, String cpu,String system) { this.model = model; this.cpu = cpu; this.system = system; } public void powerOn() { System.out.println(this.model + "正在开机"); } public void powerOff() { System.out.println(this.model + "正在关机"); } public void useSystem() { System.out.println(this.model + " 使用的是 " + this.system); } } public class PhoneNonInheritance { public static void main(String[] args) { ApplePhone iphone15ProMax = new ApplePhone("15","A17 Pro","ios"); HuaweiPhone huaweiMate40Pro = new HuaweiPhone("Mate40 Pro","麒麟9000","HarmonyOS"); XiaomiPhone xiaomi15Ultra = new XiaomiPhone("15 Ultra","SM8850","HyperOS"); iphone15ProMax.powerOn(); iphone15ProMax.powerOff(); iphone15ProMax.useSystem(); System.out.println("=================="); huaweiMate40Pro.powerOn(); huaweiMate40Pro.powerOff(); huaweiMate40Pro.useSystem(); System.out.println("=================="); xiaomi15Ultra.powerOn(); xiaomi15Ultra.powerOff(); xiaomi15Ultra.useSystem(); } }- 使用继承:
-
class Phone{ String model; String cpu; String system; public Phone(String model, String cpu,String system) { this.model = model; this.cpu = cpu; this.system = system; } public void powerOn() { System.out.println(this.model + " 正在开机"); } public void powerOff() { System.out.println(this.model + " 正在关机"); } public void useSystem() { System.out.println(this.model + " 使用的系统是 " + this.system); } } class ApplePhone extends Phone{ public ApplePhone(String model, String cpu, String system) { super(model, cpu, system); } } class HuaweiPhone extends Phone{ public HuaweiPhone(String model, String cpu, String system) { super(model, cpu, system); } } class XiaomiPhone extends Phone{ public XiaomiPhone(String model, String cpu, String system) { super(model, cpu, system); } } public class PhoneInheritance { public static void main(String[] args) { ApplePhone iphone15ProMax = new ApplePhone("Apple 15","A17 Pro","ios"); HuaweiPhone huaweiMate40Pro = new HuaweiPhone("Huawei Mate40 Pro","麒麟9000","HarmonyOS"); XiaomiPhone xiaomi15Ultra = new XiaomiPhone("Xiaomi 15 Ultra","SM8850","HyperOS"); Phone[] phones = {iphone15ProMax,huaweiMate40Pro,xiaomi15Ultra}; for (Phone phone : phones) { phone.powerOn(); phone.powerOff(); phone.useSystem(); System.out.println("=================="); } } }
-
从代码中可以明显看出,采用继承机制的实现方式大幅减少了代码量。当需要扩展手机属性时,使用继承机制只需在父类Phone中添加一次属性即可,而无需继承的方案则必须在每个子类中重复添加。这充分体现了继承机制对开发效率的提升作用。此外,若HuaweiPhone需要添加特殊属性,仅需在该子类中单独实现,完全不会影响其他两个类的功能
2.3 子类中访问父类的成员方法
当通过 extends 关键字 继承了父类的方法和字段,就可以直接访问父类的成员/方法
通过 子类对象 . 父类成员 /方法的形式访问父类成员/方法
成员方法名称不同
class Base { public void testBase() { System.out.println("调用一个无参的基类的方法"); } } class Derived extends Base { public void testDerived() { System.out.println("调用一个无参的派生类的方法"); } } public class Test { public static void main(String[] args) { Derived derived = new Derived(); derived.testBase(); derived.testDerived(); } }运行结果:
调用一个无参的基类的方法
调用一个无参的派生类的方法
成员方法名称相同
class Base { public void test() { System.out.println("调用一个无参的基类的方法"); } } class Derived extends Base { public void test() { System.out.println("调用一个无参的派生类的方法"); } } public class Test { public static void main(String[] args) { Derived derived = new Derived(); derived.test(); } }运行结果:调用一个无参的派生类的方法
【结论】
当成员方法没有同名时,通过子类对象访问成员会优先查找子类自身的成员。若子类中不存在该成员,则会继续向上在父类中查找。若父类中也不存在该成员,则会导致编译报错。
2.4 构造方法
2.4.1 子类构造方法 隐式 调用父类构造方法
- 父类 无 显示构造方法
- 子类 无 显示构造方法
此时,编译器会自动生成一个无参构造方法。具体实现如下代码所示(注释部分展示了编译器默认生成的构造方法):
class Base { /*public Base() { // 空实现 }*/ } class Derived extends Base { /*public Derived() { super();//编译器自动添加 }*/ }- 子类 有 显示构造方法
当构造方法的第一行没有显式调用 super 时,编译器会自动生成一个 super() 调用,隐式执行父类的无参构造方法。
class Base { /*public Base() { }*/ } class Derived extends Base { public Derived(int x) { super();//编译器自动添加 System.out.println("Derived()"); } }- 父类 包含 显示构造方法
- 子类 无 显示 构造方法
父类 为 无参 构造方法
此时 子类会默认生成 注释掉的内容,进行隐式调用父类无参构造方法
class Base { public Base() { //xxxxx } } class Derived extends Base { /* public Derived(int x) { super();//编译器自动添加 }*/ } 父类 为 含参 构造方法
此时 编译报错,需要进行显示调用
//error!!! class Base { public Base(int x) { //xxxxx } } class Derived extends Base { /* public Derived(int x) { super(x);//手动显示调用 }*/ }
2.4.2 子类构造方法 显式 调用父类构造方法
-
当 父类 与 子类 均显示定义了构造方法,且 父类为含参构造方法 时
-
class Base { public Base(int x) { System.out.println(x); } } class Derived extends Base { public Derived(int x) { super(x); } }
-
重要提示:在创建子类对象时,必须先调用父类的构造方法,然后再执行子类自身的构造方法。
3. 核心机制详解
- 方法重写(Override):子类重写父类方法,实现多态行为。
- 触发方式:
- 当子类与父类的方法名,参数列表一致时,便会发生方法的重写
- 触发方式:
注:
- 当子类与父类的方法名,参数列表一致时:
如果父类方法返回类型为
void,则子类也必须为 void,否则编译错误如果父类方法返回类型为基本数据类型(如
int),子类必须返回相同的基本类型,不能修改为其他类型(如long)如果父类方法返回类型为引用类型(如
Animal),子类可以返回相同类型或其子类(如Dog,假设Dog是Animal的子类),这称为协变返回类型(Java 5+ 支持)访问修饰符规则:
子类方法的访问权限必须不低于父类方法(即访问范围不能缩小)。具体规则如下:
- 当父类方法为 protected 时,子类方法可以是 protected 或 public
- 当父类方法为 public 时,子类方法必须保持 public(不能降低访问级别)
特殊说明:
对于 private 方法:由于对子类不可见,子类无法重写该方法,只能定义同名新方法(这不属于方法重写)final :
使用 final 修饰的类无法被继承,因此无法用于需要继承的场景。
| NO. | 范围 | private | default | protected | public |
| 1 | 同一包中的同一类 | √ | √ | √ | √ |
| 2 | 同一包中的不同类 | √ | √ | √ | |
| 3 | 不同包中的子类 | √ | √ | ||
| 4 | 不同包中的非子类 | √ | |||
| 0 | 权限大小 | private | <defualt | <protected | <public |
- 示例代码:
-
class Base { public void test() { System.out.println("Base-test()::调用一个无参的基类的方法"); } } class Derived extends Base { public void test() { System.out.println("Derived-test()::调用一个无参的派生类的方法"); } } public class Test { public static void main(String[] args) { Base base = new Base(); base.test(); } }运行结果:Base-test()::调用一个无参的基类的方法
-
- super关键字:在子类中访问父类成员。
- 用途:
- 调用父类成员方法/属性(super.xxx)
- 调用父类构造方法(super( ))
- 在调用父类构造方法时,super();只能在子类构造方法总的第一行
- 用途:
注意事项:
- 只能直接访问父类
super 的调用不能跨级跳转。例如,当 C 类继承 B 类,B 类又继承 A 类时,C 类通过 super 只能访问直接父类 B 的方法,无法直接访问祖父类 A 的方法。- 禁止跨级语法(super.super)
super.super 是无效语法- 间接访问祖父类的方法
在父类B中显示调用A(super.xxx),在由C间接调用
- 示例:
-
class Base { public void test() { System.out.println("Base-test()::调用一个无参的基类的方法"); } public Base() { System.out.println("Base()::调用一个无参的构造方法"); } } class Derived extends Base { public Derived() { super();//调用父类的构造方法 System.out.println("Derived()::调用一个无参的构造方法"); } public void test() { System.out.println("Derived-test()::调用一个无参的派生类的方法"); super.test();//调用父类的 test方法 } } public class Test { public static void main(String[] args) { Derived derived = new Derived(); derived.test(); } }运行结果:
Base()::调用一个无参的构造方法
Derived()::调用一个无参的构造方法
Derived-test()::调用一个无参的派生类的方法
Base-test()::调用一个无参的基类的方法
-
- final关键字:限制继承(
final class不可继承)或方法重写(final method不可重写)。
3.继承方式
现实世界中,事物之间的联系往往错综复杂且灵活多变。例如:

那么在Java中 支持的继承方式有如下几种:

在Java中 并不支持 多继承
其次 在多层继承的前提下,不建议出现超过三层的继承关系
4.继承与组合
组合和继承都能实现代码复用,但两者实现方式不同。组合不需要特定的语法(如继承中的extends关键字),而是通过将其他类作为字段来实现功能复用。
以手机制造为例:一部手机由电池、主板、CMOS、尾插、扬声器、震动马达、屏幕、SOC、UFS、RAM和通信模块等部件组成。这些部件可以由不同厂商(如Xiaomi、Apple或Huawei)进行组装,最终贴上各自的品牌标识。
在Java中理解组合:
-
每个手机部件都可以封装成独立类:
- 电池类包含型号、容量等属性
- CMOS类包含型号、尺寸、进光量等参数
-
手机厂商只需:
- 了解需要哪些组件类
- 将这些类实例组合起来
- 完成手机的整体组装
这种模块化的设计方式就是组合的典型应用。
组合示例代码
class Cmos{
String brand;//品牌
String type;//型号
public Cmos(String brand, String type) {
this.brand = brand;
this.type = type;
}
}
class Battery{
int batteryCapacity;//电池容量
String brand;//品牌
String type;//型号
public Battery(int batteryCapacity, String brand, String type) {
this.batteryCapacity = batteryCapacity;
this.brand = brand;
this.type = type;
}
}
class Soc{
String type;//型号
String brand;//品牌
public Soc(String type, String brand) {
this.type = type;
this.brand = brand;
}
}
class Phone{
private Soc soc;
private Cmos cmos;
private Battery battery;
//上述就为组合
public String brand;//手机品牌
public String type;//手机型号
public double weight;//手机重量
public String color;//手机颜色
public Phone(Soc soc, Cmos cmos, Battery battery, String brand, String type, double weight, String color) {
this.soc = soc;
this.cmos = cmos;
this.battery = battery;
this.brand = brand;
this.type = type;
this.weight = weight;
this.color = color;
}
}
public class Test {
public static void main(String[] args) {
// 创建手机组件
Soc snapdragon8Elit = new Soc("Snapdragon 8 Elit", "Qualcomm");
Cmos sonyIMX989 = new Cmos("Sony", "IMX989");
Battery xiaomiBattery = new Battery(5000, "Xiaomi", "BM58");
// 创建小米15 Ultra手机
Phone Xiaomi15Ultra = new Phone(
snapdragon8Gen3,
sonyIMX989,
xiaomiBattery,
"Xiaomi",
"15 Ultra",
225.0, // 重量(克)
"Ceramic Black" // 颜色
);
}
}
end *
2838

被折叠的 条评论
为什么被折叠?



