Java反射与ReflectASM性能对比
这是几年前写的旧文,此前发布Wordpress小站上,现在又重新整理。算是温故知新,后续会继续整理。如有错误望及时指出,在此感谢。
在日常的开发中,我们经常会用到反射。Java语言提供的反射机制能非常方便的让我们在运行时进动态调用和修改。同时第三方ReflectASM也是字节码生成工具,可以达到反射的效果。
那么今天就来比较下两者的性能差异。
需求描述
比较Java反射与ReflectASM的性能差异
环境准备
Jkd1.8
//Maven依赖
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>reflectasm</artifactId>
<version>1.11.0</version>
</dependency>
测试场景
准备一个POJO,通过反射机制在运行时不断修改类的实例,最后统计耗时
代码
import com.esotericsoftware.reflectasm.FieldAccess;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
class CarPojo {
String carColor;
String carName;
int carSize;
boolean isSale;
public String getCarColor() {
return carColor;
}
public void setCarColor(String carColor) {
this.carColor = carColor;
}
public String getCarName() {
return carName;
}
public void setCarName(String carName) {
this.carName = carName;
}
public int getCarSize() {
return carSize;
}
public void setCarSize(int carSize) {
this.carSize = carSize;
}
public boolean isSale() {
return isSale;
}
public void setIsSale(boolean sale) {
isSale = sale;
}
@Override
public String toString() {
return "Car{" +
"carColor='" + carColor + '\'' +
", carName='" + carName + '\'' +
", carSize=" + carSize +
", isSale=" + isSale +
'}';
}
}
class DataTypeDesc implements Serializable {
private static final long serialVersionUID = -6661934820005192771L;
String fieldName;
String fieldType;
String fieldValue;
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getFieldType() {
return fieldType;
}
public void setFieldType(String fieldType) {
this.fieldType = fieldType;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
public DataTypeDesc() {
}
public DataTypeDesc(String fieldName, String fieldType, String fieldValue) {
this.fieldName = fieldName;
this.fieldType = fieldType;
this.fieldValue = fieldValue;
}
}
/**
* 通过反射进行对象赋值
*/
public class JavaReflectTest1 {
public static void main(String[] args) throws Exception {
Set<DataTypeDesc> inputData = new HashSet<DataTypeDesc>();
DataTypeDesc d1 = new DataTypeDesc();
d1.setFieldName("carColor");
d1.setFieldType("STRING");
d1.setFieldValue("blue");
DataTypeDesc d2 = new DataTypeDesc();
d2.setFieldName("carName");
d2.setFieldType("STRING");
d2.setFieldValue("大众");
DataTypeDesc d3 = new DataTypeDesc();
d3.setFieldName("carSize");
d3.setFieldType("INT");
d3.setFieldValue("11");
DataTypeDesc d4 = new DataTypeDesc();
d4.setFieldName("isSale");
d4.setFieldType("BOOLEAN");
d4.setFieldValue("true");
inputData.add(d1);
inputData.add(d2);
inputData.add(d3);
inputData.add(d4);
final int count = 10000000;
long start_1 = System.nanoTime();
for (int i = 0; i < count; i++) {
String str1 = testJdkReflect(CarPojo.class, inputData);
}
long stop_1 = System.nanoTime();
float duration1 = (stop_1 - start_1) / 1000000000.0F;
System.out.println("testJdkReflect duration(s):" + duration1);
//testJdkReflect duration(s):13.564455
long start_2 = System.nanoTime();
for (int i = 0; i < count; i++) {
String str2 = testAsmReflect(CarPojo.class, inputData);
}
long stop_2 = System.nanoTime();
float duration2 = (stop_2 - start_2) / 1000000000.0F;
System.out.println("testAsmReflect duration(s):" + duration2);
//testAsmReflect duration(s):8.446463
System.out.println("duration diff(s):" + (duration1 - duration2) / duration1);
//duration diff(s):0.3773091
}
public static <T> String testJdkReflect(Class<T> clazz, Set<DataTypeDesc> inputData) throws Exception {
//获取类中声明的所有字段
// Field[] fields = clazz.getDeclaredFields();
//创建新的实例对象
T instance = clazz.newInstance();
DataTypeDesc dataType = null;
Iterator<DataTypeDesc> iterator = inputData.iterator();
while (iterator.hasNext()) {
//获取字段的名称
// String fieldName = fields[i].getName();
dataType = iterator.next();
if (dataType != null) {
String fieldName = dataType.getFieldName();
String fieldType = dataType.getFieldType();
String fieldValue = dataType.getFieldValue();
//把序列化id筛选掉
if (fieldName.equals("serialVersionUID")) {
continue;
}
//获取字段的类型
Class<?> fieldTypeClass = clazz.getDeclaredField(fieldName).getType();
// 首字母大写
String nameUpper = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
//获得setter方法
Method setMethod = clazz.getMethod("set" + nameUpper, fieldTypeClass);
//通过setter方法赋值给对应的成员变量
if (!fieldValue.isEmpty()) {
//判断读取数据的类型
if (fieldType.equalsIgnoreCase("STRING") && fieldTypeClass.isAssignableFrom(String.class)) {
//String处理
setMethod.invoke(instance, fieldValue);
}
if (fieldType.equalsIgnoreCase("INT")
&& (fieldTypeClass.isAssignableFrom(int.class) || fieldTypeClass.isAssignableFrom(Integer.class))
) {
//int处理
setMethod.invoke(instance, Integer.parseInt(fieldValue));
}
if (fieldType.equalsIgnoreCase("BOOLEAN")
&& (fieldTypeClass.isAssignableFrom(Boolean.class) || fieldTypeClass.isAssignableFrom(boolean.class))
) {
//boolean处理
//这里要注意,对于boolean类型,自动生成的set方法名可能会不符合我们的判断,需要修正
setMethod.invoke(instance, Boolean.parseBoolean(fieldValue));
}
}
}
}
String json = instance.toString();
return json;
}
public static <T> String testAsmReflect(Class<T> clazz, Set<DataTypeDesc> inputData) throws Exception {
T target = clazz.newInstance();
DataTypeDesc dataType = null;
Iterator<DataTypeDesc> iterator = inputData.iterator();
FieldAccess fieldAccess = FieldAccess.get(target.getClass());
while (iterator.hasNext()) {
dataType = iterator.next();
if (dataType != null) {
String fieldName = dataType.getFieldName();
String fieldType = dataType.getFieldType();
String fieldValue = dataType.getFieldValue();
Object v = null;
//判断读取数据的类型
if (fieldType.equalsIgnoreCase("STRING")) {
//String处理
v = fieldValue;
}
if (fieldType.equalsIgnoreCase("INT")) {
//int处理
v = Integer.parseInt(fieldValue);
}
if (fieldType.equalsIgnoreCase("BOOLEAN")) {
//boolean处理
v = Boolean.parseBoolean(fieldValue);
}
fieldAccess.set(target, fieldName, v);
}
}
String s = target.toString();
return s;
}
}
总结
这里进行的测试并不严谨,没有考虑让JVM进行字节码运行时编译等行为。从测试结果看出,使用Asm进行字节码生成的方式进行反射操作,还是要比Java自带的反射性能要好35%以上。