一、继承的本质:消除冗余,构建逻辑关系
想象一个公司管理系统:普通销售员工(
CommissionEmployee
)和带底薪销售员工(BasePlusCommissionEmployee
)共享大部分属性(姓名、工号、销售额、佣金率)。没有继承时,代码会变成这样:
// 普通销售员工类
class CommissionEmployee {private String name;private String identityNumber;private double grossSales;private double commissionRate;// 构造器和方法...
}// 带底薪销售员工类
class BasePlusCommissionEmployee {private String name; // 重复private String identityNumber; // 重复private double grossSales; // 重复private double commissionRate; // 重复private double baseSalary; // 特有属性// 构造器和方法...
}
这种设计存在三大问题:
- 代码冗余:相同属性在多处重复
- 维护成本高:修改公共属性需同步所有类
- 关系缺失:未体现"带底薪员工也是销售员工"的逻辑
继承解决方案:
class CommissionEmployee { /* 公共属性 */ }
class BasePlusCommissionEmployee extends CommissionEmployee { private double baseSalary; // 仅定义特有属性
}
二、访问控制:protected与封装的艺术
继承中,子类如何访问父类属性?核心在于访问修饰符:
class Parent {private int x; // 仅本类可访问protected int y; // 子类可访问
}class Child extends Parent {void demo() {// System.out.println(x); // 错误!private不可访问System.out.println(y); // 正确,protected允许访问}
}
最佳实践:
class CommissionEmployee {private double grossSales; // 保持封装// 通过protected方法暴露访问protected double getGrossSales() { return grossSales; }
}class BasePlusCommissionEmployee extends CommissionEmployee {@Overridepublic double earnings() {// 通过getter安全访问父类属性return baseSalary + getGrossSales() * getCommissionRate();}
}
三、构造器:super()的初始化魔法
子类必须通过super()
调用父类构造器,确保继承链完整:
class Employee {public Employee(String name, String id) {System.out.println("初始化员工基础信息");}
}class Manager extends Employee {private String department;public Manager(String name, String id, String dept) {super(name, id); // 必须第一行this.department = dept;System.out.println("添加经理专属属性");}
}
多级继承初始化顺序:
class Person {public Person() { System.out.println("Person初始化"); }
}
class Employee extends Person {public Employee() { System.out.println("Employee初始化"); }
}
class Manager extends Employee {public Manager() { System.out.println("Manager初始化"); }
}
// 创建Manager时输出:
// Person初始化 → Employee初始化 → Manager初始化
四、方法重写:@Override的力量
当子类需要改变父类行为时,使用方法重写:
class Vehicle {public void startEngine() {System.out.println("启动普通引擎");}
}class ElectricCar extends Vehicle {@Overridepublic void startEngine() {System.out.println("静默启动电机"); // 完全重写}
}class HybridCar extends Vehicle {@Overridepublic void startEngine() {super.startEngine(); // 复用父类逻辑System.out.println("同时启动电机"); // 扩展新功能}
}
重写 vs 重载:
// 重写(父子类间)
class Parent { void demo(int a) {} }
class Child extends Parent { @Override void demo(int a) {} // 相同签名
}// 重载(同一类内)
class Calculator {int add(int a, int b) { ... } // 签名1double add(double a, double b) { ... } // 签名2
}
五、类层次设计:从Object到业务模型
所有Java类都隐式继承Object,可重写关键方法:
class Employee {private String name;@Overridepublic String toString() {return "员工: " + name; // 替换默认的类名@哈希值}
}
设计原则:
- 单一职责:每层添加明确的新功能
- 层次扁平化:建议≤3层(如:Person→Employee→Manager)
- 组合优于继承:当"has-a"比"is-a"更合理时
六、实战:可运行的继承案例
// 基类(父类)
class MyParent {protected int x, y; // 子类可访问的受保护属性public MyParent(int x, int y) {this.x = x;this.y = y;}public int getX() { return x; }public int getY() { return y; }
}// 派生类(子类)
class MyChild extends MyParent {public MyChild(int x, int y) {super(x, y); // 必须调用父类构造器}// 子类特有方法public int calculateSum() {return x + y; // 直接访问父类protected属性}
}// 测试类
public class Main {public static void main(String[] args) {MyChild obj = new MyChild(5, 3);System.out.println("从父类继承的方法:");System.out.println("x = " + obj.getX()); // 输出: 5System.out.println("y = " + obj.getY()); // 输出: 3System.out.println("子类特有方法:");System.out.println("x+y = " + obj.calculateSum()); // 输出: 8}
}
执行结果:
从父类继承的方法:
x = 5
y = 3
子类特有方法:
x+y = 8
七、继承的四大核心价值
代码复用:
// 公共代码在父类写一次
class Animal {void breathe() { System.out.println("呼吸中..."); }
}
// 所有子类自动获得呼吸能力
class Fish extends Animal {}
class Bird extends Animal {}
多态支持:
Animal[] zoo = {new Fish(), new Bird()};
for(Animal a : zoo) {a.breathe(); // 不同子类统一调用
}
扩展灵活:
class Bird extends Animal {@Overridevoid breathe() {super.breathe();System.out.println("气囊辅助呼吸"); // 扩展功能}
}
系统可维护性:
结语:明智使用继承
继承是把双刃剑,遵循三条黄金法则:
- 严格验证"is-a"关系(经理是员工✓,员工是公司✗)
- 优先用组合处理"has-a"关系(汽车有发动机→组合)
- 保持层次扁平(超过3层需重构)