Java基础(八):封装、继承、多态性实战解析
1. 封装性实战解析
封装是面向对象编程的第一道防线,它像保险箱一样保护着数据安全。我见过太多新手直接暴露成员变量导致数据混乱的案例,比如下面这个反面教材:
// 危险示范:裸奔的成员变量 class Employee { public String name; public double salary; }正确的封装姿势应该是这样的:
public class Employee { private String name; private double baseSalary; // 薪资校验逻辑 public void setBaseSalary(double salary) { if(salary < 0) { throw new IllegalArgumentException("薪资不能为负数"); } this.baseSalary = salary; } // 计算税后工资(隐藏计算细节) public double getNetSalary() { return baseSalary * 0.85; // 模拟扣除15%税费 } }封装的核心价值在于:
- 数据校验:像门卫一样检查数据合法性
- 隐藏实现:修改内部计算逻辑不影响调用方
- 访问控制:通过权限修饰符管理可见性
四种访问修饰符的权限对比:
| 修饰符 | 本类 | 同包 | 不同包子类 | 不同包非子类 |
|---|---|---|---|---|
| private | ✅ | ❌ | ❌ | ❌ |
| 缺省 | ✅ | ✅ | ❌ | ❌ |
| protected | ✅ | ✅ | ✅ | ❌ |
| public | ✅ | ✅ | ✅ | ✅ |
2. 继承体系构建技巧
继承不只是代码复用,更是构建类层次关系的艺术。我们以薪资管理系统为例:
// 基础员工类 class Employee { private String id; private String name; public Employee(String id, String name) { this.id = id; this.name = name; } public double calculateSalary() { return 0; } } // 经理类继承员工 class Manager extends Employee { private double bonus; public Manager(String id, String name, double bonus) { super(id, name); // 必须调用父类构造器 this.bonus = bonus; } @Override public double calculateSalary() { return 10000 + bonus; // 基础薪资+奖金 } }继承使用中的黄金法则:
- 里氏替换原则:子类必须能替换父类
- 慎用继承:优先考虑组合而非继承
- 避免多层继承:一般不超过3层继承链
常见误区警示:
- 子类构造器必须调用super()
- 父类private成员不可直接访问
- 方法重写时访问权限不能更严格
3. 多态性的魔法
多态让代码像变形金刚一样灵活。来看个薪资计算的经典案例:
public class SalarySystem { public static void main(String[] args) { Employee[] staff = { new Manager("M001", "张总", 5000), new Programmer("P001", "李工", 10) }; // 多态调用 for(Employee e : staff) { System.out.println(e.getName() + "的薪资:" + e.calculateSalary()); } } } class Programmer extends Employee { private int overtimeHours; public Programmer(String id, String name, int hours) { super(id, name); this.overtimeHours = hours; } @Override public double calculateSalary() { return 8000 + overtimeHours * 100; // 基础+加班费 } }多态的实现机制:
- 向上转型:
Employee e = new Manager() - 动态绑定:运行时确定实际类型
- 方法表:JVM通过虚方法表实现
类型转换的注意事项:
if(employee instanceof Manager) { Manager m = (Manager)employee; // 安全向下转型 m.approveLeave(); // 调用子类特有方法 }4. 综合案例:薪资管理系统
让我们用三大特性构建完整系统:
// 抽象基类 abstract class Employee { // 公共字段和方法... public abstract double calculateSalary(); } // 接口定义行为 interface BonusEligible { double calculateBonus(); } // 销售类实现多继承 class Sales extends Employee implements BonusEligible { private double salesAmount; @Override public double calculateSalary() { return 3000 + salesAmount * 0.1; } @Override public double calculateBonus() { return salesAmount > 10000 ? 2000 : 1000; } }系统设计要点:
- 抽象类定义公共模板
- 接口扩展额外能力
- 枚举管理类型常量
测试用例:
Employee emp = new Sales("S001", "王销售", 15000); if(emp instanceof BonusEligible) { BonusEligible be = (BonusEligible)emp; System.out.println("奖金:" + be.calculateBonus()); }5. 常见问题解决方案
问题1:如何选择继承还是接口?
- 继承:is-a关系,代码复用
- 接口:has-a能力,多态扩展
问题2:多态性能优化
- 避免频繁instanceof检查
- 使用策略模式替代条件判断
问题3:构造器链调用
public class Director extends Manager { public Director(String id, String name) { super(id, name, 0); // 必须放在第一行 // 其他初始化... } }实际项目中,我推荐使用Lombok简化代码:
@Data @AllArgsConstructor public class Department { private String name; private List<Employee> staff; }