Java开发疑问:选择IF语句还是多态?性能与代码优雅性权衡
我从事Java开发不足一年,近期在使用面向对象原则优化代码时产生疑问:用多态让代码更简洁的同时,会不会增加处理时间?比如下面的代码场景中,使用IF语句会不会因为不需要内存指针操作而性能更优?
示例代码
import java.util.ArrayList; import java.util.List; public class EscritorioContabilidade { //使用最糟糕的IF语句方式获取员工薪资信息....哈哈 public double getSalarioFuncionario(String tipoFuncionario){ double salario = -1; if("gerente".equals(tipoFuncionario)){ salario = 1000; } else if("balconista".equals(tipoFuncionario)){ salario = 900; } else if("faixineiro".equals(tipoFuncionario)){ salario = 550; } return salario; } //使用IF语句获取员工薪资信息,改进不大 public double getSalarioFuncionario(Object funcionario){ double salario = -1; if(funcionario instanceof Gerente){ salario = 1000; } else if(funcionario instanceof Balconista){ salario = 900; } else if(funcionario instanceof Faixineiro){ salario = 550; } return salario; } //使用多态获取员工薪资信息,这才对! public double getSalarioFuncionario(Funcionario funcionario){ return funcionario.informarSalario(); } public static void main(String [] asdf){ EscritorioContabilidade escritorioContabilidade = new EscritorioContabilidade(); double folhaPagamento = 0; List<Funcionario> listaFuncionario = new ArrayList<Funcionario>(); //添加员工 listaFuncionario.add(new Gerente()); listaFuncionario.add(new Balconista()); listaFuncionario.add(new Faixineiro()); //使用多态计算薪资总额 for (Funcionario funcionario : listaFuncionario) { folhaPagamento += escritorioContabilidade.getSalarioFuncionario(funcionario); } System.out.println("folha de pagamento: "+folhaPagamento); //现在使用其中一种IF语句方法,你可以对比两段代码的清晰度 folhaPagamento = 0; folhaPagamento += escritorioContabilidade.getSalarioFuncionario("gerente"); folhaPagamento += escritorioContabilidade.getSalarioFuncionario("balconista"); folhaPagamento += escritorioContabilidade.getSalarioFuncionario("faixineiro"); System.out.println("folha de pagamento: "+folhaPagamento); } } public abstract class Funcionario { public abstract double informarSalario(); } public class Gerente extends Funcionario { @Override public double informarSalario() { return 1000; } } class Balconista extends Funcionario{ @Override public double informarSalario() { return 900; } } class Faixineiro extends Funcionario{ @Override public double informarSalario() { return 550; } }
核心结论与分析
在这个场景里,多态的性能不仅不会比IF语句差,甚至可能更优,而且代码可维护性的优势是决定性的,具体原因如下:
多态的底层开销远小于IF分支
Java的多态通过方法表(vtable)实现,调用重写方法时只是一次方法表的索引查找,这个操作的开销极小。而你的两个IF版本:- 字符串判断版本:每次要执行字符串
equals比对,涉及字符数组的遍历,开销远大于多态调用; - instanceof判断版本:虽然比字符串比对快,但
instanceof本身需要做类型检查,加上分支判断的开销,整体并不比多态调用高效。
- 字符串判断版本:每次要执行字符串
JVM的即时编译会抹平性能差异
现代JVM(如HotSpot)的即时编译(JIT)会对频繁执行的代码做深度优化,其中就包括去虚拟化:如果JVM能确定某个Funcionario实例的具体类型,会直接把多态调用替换成子类方法的直接调用,性能和直接调用子类方法完全一致。而IF语句的分支判断,当分支数量增加时,JVM的分支预测准确率会下降,反而可能带来性能损耗。代码可维护性的价值远超微乎其微的性能差异
当员工类型只有3种时,IF语句看起来还能应付,但如果后续新增10种甚至更多类型,你需要不断修改getSalarioFuncionario方法,违反了开闭原则(对扩展开放、对修改关闭)。而多态的方式,新增员工类型只需要创建一个Funcionario的子类,实现informarSalario方法即可,原有业务代码完全不需要改动,扩展性、可读性都强太多。
总结
不要为了几乎可以忽略的性能差异,放弃面向对象设计带来的代码可维护性和扩展性。在绝大多数业务场景下,多态的优势远大于所谓的性能损耗。只有在极端的性能敏感场景(如每秒百万级调用的核心循环),才需要考虑底层优化,但那时也有更有效的手段,而非放弃OO原则。
内容的提问来源于stack exchange,提问作者Vinícius Alves

