我有两个班级:
abstract class Employee{
protected int id;
public int getId(){
return id;
}
}
class Manager extends Employee{
}
在执行我的应用程序的其余部分的过程中,我创建了许多员工对象并多次调用他们的getId()方法。
执行时间约为8秒。但是,如果我将以下方法添加到Manager:
@Override
public int getId(){
return super.id;
}
..相同的程序(保持其他一切不变)现在运行的时间减少了一半。我多次测试了两个版本并得到了相同的结果。谁能想到这个的原因呢?
答案 0 :(得分:3)
当您运行微基准测试时,您很容易受到基准测试的影响以及可以优化的代码。这意味着基本相同的代码可以如此微妙但性能相对较大。但是,如果您稍微改变一下测试或使用不同的Java更新,您可能会发现一个非常不同的结果。
当您覆盖子类中的方法时,您可以有效地使该类成为虚拟。这意味着您可以调用Employee.getId()
或Manager.getId()
,并且需要检查类型以确定要调用的类方法。方法相同的事实并没有帮助。 JVM可以相当智能并且内联方法,但由于您的方法很简单,因此非常简单的类型检查可能意味着性能的差异。
这种变化也可能会导致其他优化。例如,如果长度为35个字节,则只会内联“不常见”。这可能会导致try / catch块出现问题。 try / catch块本身并不会减慢代码速度,但可以使方法更大并且意味着它不再内联。在你的情况下,有一个覆盖方法可能意味着当你的方法被内联并且它没有被积极地优化时,调用代码会更大。
最后,我会用最新的JVM检查你的代码。例如Java 7更新40.您可能会发现此版本没有显示出差异,在这种情况下,我会将其归结为您的JVM版本中的错误。
答案 1 :(得分:1)
非常有趣,
为了确认自己,我创建了测试用例,以复制行为,在测试用例和测试结果下方给出
案例1未覆盖方法
测试结果
运行1 - 创建100000000员工完成操作所需的时间:501(ms)
运行2 - 创建100000000员工完成操作所需的时间:507(ms)
运行3 - 创建100000000员工完成操作所需的时间:502(ms)
案例2 - 重写子类中的方法
@Override
public int getId(){
return super.id;
}
Test Result
运行1 - 创建100000000员工完成操作所需的时间:486(ms)
运行2 - 创建100000000员工完成操作所需的时间:497(ms)
运行3 - 创建100000000员工完成操作所需的时间:478(ms)
案例3 - 覆盖方法,但不使用超级关键字
@Override
public int getId(){
return id;
}
测试结果
运行1 - 创建100000000名员工 完成操作所需的时间:457(ms)
运行2 - 创建100000000名员工 完成操作所需的时间:471(ms)
运行3 - 创建100000000名员工 完成操作所需的时间:471(ms)
<强>观察:强>
在重写方法/直接使用时(案例2和案例3),改进很小;但作为最佳实践,大多数情况下变量将被声明为私有,方法将受到保护。如果变量本身受到保护,那么您将需要超级密钥
----------完整测试代码供参考-----
public class TestEff {
public static void main(String[] args) {
System.out.println( " Creating 100000000 Employees ");
long st = System.currentTimeMillis();
for(int i=0;i<100000000;i++){
Manager mgr = new Manager();
int id =mgr.getId();
}
long et = System.currentTimeMillis();
long t = (et-st);
System.out.println(" Time taken to complete operation :"+t);
}
}
abstract class Employee{
protected int id;
public int getId(){
return id;
}
}
班级经理扩展员工{ @覆盖 public int getId(){ 返回super.id; } }