Java 调用超级类的getter会降低效率吗?
我有两门课:Java 调用超级类的getter会降低效率吗?,java,performance,inheritance,Java,Performance,Inheritance,我有两门课: abstract class Employee{ protected int id; public int getId(){ return id; } } class Manager extends Employee{ } 在应用程序其余部分的执行过程中,我创建了许多employee对象并多次调用它们的getId()方法 执行时间约为8秒。但如果我向Manager添加以下方法: @Override public int
abstract class Employee{
protected int id;
public int getId(){
return id;
}
}
class Manager extends Employee{
}
在应用程序其余部分的执行过程中,我创建了许多employee对象并多次调用它们的getId()方法
执行时间约为8秒。但如果我向Manager添加以下方法:
@Override
public int getId(){
return super.id;
}
…同样的程序(保持所有其他内容不变)现在运行的时间是原来的一半。我对这两个版本进行了多次测试,得到了相同的结果。有人能想出这样做的原因吗?当你运行一个微基准测试时,你很容易受到你如何执行基准测试以及哪些代码可以优化的影响。这意味着基本相同的代码可能会在性能上存在细微但相对较大的差异。但是,如果您以稍微不同的方式进行测试,或者使用不同的Java更新,您可能会发现非常不同的结果 当重写子类中的方法时,可以有效地使该类成为虚拟类。这意味着您可以调用
Employee.getId()
或Manager.getId()
,它需要检查类型以确定要调用哪个类方法。这些方法是相同的,这一事实没有帮助。JVM可以相当智能并内联该方法,但由于您的方法很简单,因此非常简单的类型检查可能意味着性能上的差异
这一变化也可能导致其他优化。例如,“不频繁”只有在长度为35字节时才内联。这可能会导致try/catch块出现问题。try/catch块本身不会减慢代码的速度,但会使方法变大,并意味着它不再是内联的。在您的情况下,如果您的方法是内联的,那么拥有一个被重写的方法可能意味着调用代码要大一点,并且没有进行积极的优化
最后,我将使用最新的JVM检查您的代码。e、 Java 7更新40。您可能会发现,这个版本没有显示任何差异,在这种情况下,我将把它归结为JVM版本中的一个错误。当您运行微基准测试时,您非常容易受到如何执行基准测试以及可以优化哪些代码的影响。这意味着基本相同的代码可能会在性能上存在细微但相对较大的差异。但是,如果您以稍微不同的方式进行测试,或者使用不同的Java更新,您可能会发现非常不同的结果 当重写子类中的方法时,可以有效地使该类成为虚拟类。这意味着您可以调用
Employee.getId()
或Manager.getId()
,它需要检查类型以确定要调用哪个类方法。这些方法是相同的,这一事实没有帮助。JVM可以相当智能并内联该方法,但由于您的方法很简单,因此非常简单的类型检查可能意味着性能上的差异
这一变化也可能导致其他优化。例如,“不频繁”只有在长度为35字节时才内联。这可能会导致try/catch块出现问题。try/catch块本身不会减慢代码的速度,但会使方法变大,并意味着它不再是内联的。在您的情况下,如果您的方法是内联的,那么拥有一个被重写的方法可能意味着调用代码要大一点,并且没有进行积极的优化
最后,我将使用最新的JVM检查您的代码。e、 Java 7更新40。您可能会发现这个版本没有显示任何差异,在这种情况下,我可以将其归结为JVM版本中的一个错误。非常有趣
为了证实我自己,我创建了测试用例,以复制下面给出的测试用例和测试结果的行为
不重写方法时的情况1
@Override
public int getId(){
return id;
}
测试结果
运行1-创建100000000名员工完成操作所需时间:501(毫秒)
运行2-创建100000000名员工完成操作所需时间:507(毫秒)
运行3-创建100000000名员工完成操作所需的时间:502(毫秒)
案例2-重写子类中的方法时,
@Override
public int getId(){
return super.id;
}
Test Result
运行1-创建100000000名员工完成操作所需时间:486(毫秒)
运行2-创建100000000名员工完成操作所需时间:497(毫秒)
运行3-创建100000000名员工完成操作所需时间:478(毫秒)
案例3-覆盖方法,但不使用超级关键字
@Override
public int getId(){
return id;
}
测试结果
运行1-创建100000000名员工
完成操作所需时间:457(毫秒)
运行2-创建100000000名员工
完成操作所需时间:471(毫秒)
运行3-创建100000000名员工
完成操作所需时间:471(毫秒)
观察:
当重写方法/直接使用时(案例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;
}
}
公共类TestEff{
公共静态void main(字符串[]args){
System.out.println(“创建100000000名员工”);
long st=System.currentTimeMillis();
对于(inti=0;i非常有趣
为了证实我自己,我创建了测试用例,以复制下面给出的测试用例和测试结果的行为
不重写方法时的情况1
@Override
public int getId(){
return id;
}
测试结果
运行1-创建100000000名员工完成操作所需时间:501(毫秒)
运行2-创建100000000名员工完成操作所需时间:507(毫秒)
运行3-创建100000000名员工完成操作所需的时间:502(毫秒)
情况2-在中重写方法时