Employee 类必须是 abstract,因为其 calculateSalary() 方法无法统一实现,若不声明为抽象类则允许非法实例化,导致多态失效;该方法不可为 static,否则无法动态绑定子类实现;字段应按共用性合理分布,测试时需避免 double 类型直接用 == 比较。

为什么 Employee 类必须是 abstract
直接 new Employee 会导致编译错误,因为薪资计算逻辑在父类里没法统一实现——经理和实习生的工资结构完全不同。不加 abstract,编译器会允许你实例化一个“说不清怎么算工资”的员工,后续多态就失效了。
常见错误现象:java.lang.Error: Unresolved compilation problem: Cannot instantiate the type Employee
- 所有含未实现
calculateSalary()的父类,必须声明为abstract class Employee - 子类要么实现该方法,要么也声明为
abstract(但通常不这么做) - 接口也能定义行为,但这里需要共享字段(如
name、baseSalary),用抽象类更自然
calculateSalary() 方法不能是 static
多态靠的是运行时对象的实际类型决定调用哪个版本的方法。如果写成 static,JVM 看的是引用类型,不是实例类型——Employee e = new Manager(...); e.calculateSalary() 会永远调用 Employee 里的 static 版本,彻底绕过子类逻辑。
使用场景:你希望同一段处理代码(比如遍历 List<Employee>)自动适配不同员工类型的计算规则。
立即学习“Java免费学习笔记(深入)”;
- 务必去掉
static修饰符 - 确保子类重写时方法签名完全一致(返回值、参数、名称),否则不是重写而是重载
- 加上
@Override注解,编译器能帮你揪出拼写或参数错误
Manager 和 Intern 的字段设计差异
字段要不要放在父类,取决于是否所有子类都共用。比如 bonus 只有经理有,硬塞进 Employee 会让实习生对象多占内存、语义混乱;而 baseSalary 大家都有,放父类最干净。
性能影响:字段冗余不会拖慢计算,但会增加对象大小和 GC 压力,尤其当员工数量上万时。
-
Manager单独加private double bonus,构造时传入 -
Intern加private int daysWorked和private double dailyRate,避免用baseSalary硬套 - 父类只保留真正通用的字段:
protected String name、protected double baseSalary
测试时别用 == 比较 salary 计算结果
浮点数运算存在精度误差,比如 1000.0 * 1.2 可能得 1200.0000000000002。用 == 判断两个 double 是否相等,极大概率失败。
常见错误现象:单元测试里 assertThat(manager.calculateSalary(), is(1200.0)) 突然红了,但打印出来看起来一模一样。
- 改用
assertEquals(expected, actual, delta),例如assertEquals(1200.0, manager.calculateSalary(), 0.01) - 或者把金额转成
int分单位处理(推荐用于真实薪资系统) - 不要在
toString()或日志里依赖==判断业务逻辑是否正确
多态本身不难,难的是在加字段、改方法、写测试时,下意识忽略类型实际是什么——尤其是 static 和 == 这两个坑,一次写错,后面花三倍时间找。










