反射效率为什么低

最近看spring源码相关内容,看到aop的实现,其中有动态代理涉及到反射内容,总有帖子说反射效率低,所以就想验证下反射效率是否整点低,以及低到什么程度?是否只要使用就很影响性能?

验证反射效率

代码

实体类

package org.springframework.test.reflect;

public class ReflectA {
private int age;
public String name;
private String sex;

public ReflectA(int age, String name, String sex) {

this.age = age;
this.name = name;
this.sex = sex;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}
}

测试类

package org.springframework.test.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* 测试反射效率
*/
public class TestEfficiency {
private static final int AVERAGE_COUNT = 10;
private static final int executeCount = 1000;
public static void main(String[] args) {
long costTime = 0;
long reflectMethodCostTime=0,normalMethodCostTime=0,reflectFieldCostTime=0,normalFieldCostTime=0;
for(int index = 0; index < AVERAGE_COUNT; index++){

costTime = getNormalCallCostTime(executeCount);
reflectMethodCostTime += costTime;

costTime = getReflectCallMethodCostTime(executeCount);
normalMethodCostTime += costTime;

costTime = getNormalFieldCostTime(executeCount);
reflectFieldCostTime += costTime;

costTime = getReflectCallFieldCostTime(executeCount);
normalFieldCostTime += costTime;
}

System.out.println("reflectMethodCostTime: " + reflectMethodCostTime/AVERAGE_COUNT + " ms");
System.out.println("normalMethodCostTime: " + normalMethodCostTime/AVERAGE_COUNT + " ms");
System.out.println("reflectFieldCostTime: " + reflectFieldCostTime/AVERAGE_COUNT + " ms");
System.out.println("normalFieldCostTime: " + normalFieldCostTime/AVERAGE_COUNT + " ms");
}
private static long getReflectCallMethodCostTime(int count){
long startTime = System.currentTimeMillis();
for(int index = 0 ; index < count; index++){
ReflectA a = new ReflectA(12,"小明", "男");
try{
Method setName = a.getClass().getMethod("setName", String.class);
setName.setAccessible(true);
setName.invoke(a, "张三");
}catch(IllegalAccessException e){
e.printStackTrace();
}catch(InvocationTargetException e){
e.printStackTrace();
}catch(NoSuchMethodException e){
e.printStackTrace();
}
}

return System.currentTimeMillis()-startTime;
}

private static long getReflectCallFieldCostTime(int count){
long startTime = System.currentTimeMillis();
for(int index = 0 ; index < count; index++){
ReflectA a = new ReflectA(12,"小明", "男");
try{
Field ageField = a.getClass().getDeclaredField("name");
ageField.set(a, "李四");
}catch(NoSuchFieldException e){
e.printStackTrace();
}catch(IllegalAccessException e){
e.printStackTrace();
}
}

return System.currentTimeMillis()-startTime;
}

private static long getNormalCallCostTime(int count){
long startTime = System.currentTimeMillis();
for(int index = 0 ; index < count; index++){
ReflectA a = new ReflectA(12,"小明", "男");
a.setName("王五");
}

return System.currentTimeMillis()-startTime;
}

private static long getNormalFieldCostTime(int count){
long startTime = System.currentTimeMillis();
for(int index = 0 ; index < count; index++){
ReflectA a = new ReflectA(12,"小明", "男");
a.name = "候六";
}

return System.currentTimeMillis()-startTime;
}
}

输出结论

  • 反射10次
  • reflectMethodCostTime: 0 ms
  • normalMethodCostTime: 0 ms
  • reflectFieldCostTime: 0 ms
  • normalFieldCostTime: 0 ms
  • 反射100次
  • reflectMethodCostTime: 0 ms
  • normalMethodCostTime: 0 ms
  • reflectFieldCostTime: 0 ms
  • normalFieldCostTime: 0 ms
  • 反射1000次
  • reflectMethodCostTime: 1 ms
  • normalMethodCostTime: 0 ms
  • reflectFieldCostTime: 1 ms
  • normalFieldCostTime: 0 ms
  • 反射10000次
  • reflectMethodCostTime: 7 ms
  • normalMethodCostTime: 0 ms
  • reflectFieldCostTime: 5 ms
  • normalFieldCostTime: 0 ms
  • 反射100000次
  • reflectMethodCostTime: 23 ms
  • normalMethodCostTime: 1 ms
  • reflectFieldCostTime: 17 ms
  • normalFieldCostTime: 1 ms
  • 反射1000000次
  • reflectMethodCostTime: 77 ms
  • normalMethodCostTime: 2 ms
  • reflectFieldCostTime: 31 ms
  • normalFieldCostTime: 2 ms

结论

  • 1.反射确实会比正常访问效率低
  • 2.反射在100以内,对于性能的影响是可以忽略的,反射100-1000次之间存在一个反射影响效率的阈值
  • 3.整体比较来看直接访问属性和直接通过方法访问属性效率较高,其次是反射获取属性,最后是反射获取方法。