Java 中反射、内省的性能差距居然如此

开发 前端
基准测试的几种情况已经准备好了,为了达到更充分的验证,我们分别循环执行10、100、200、500次,我们跑一下基准测试看看效果。

你好,我是看山。

今天我们通过基准测试验证下到底有多慢。

结果是我万万没想到的,跑了好几遍基准测试,不得不承认之前是自己不严谨了。

演示代码

先定义使用场景:为一个JavaBean的属性赋值。

@Data
public static class User {
    private String username;
    private int level;
}

为User的属性赋值,我们有三种方式。

原生方式,作为基准:

final User user = new User();
user.setUsername("看山");
user.setLevel(100);

通过反射:

final Class<User> clazz = User.class;
final Constructor<User> constructor = clazz.getConstructor();
final User user = constructor.newInstance();

final Field usernameField = clazz.getDeclaredField("username");
usernameField.setAccessible(true);
usernameField.set(user, "看山");
final Field levelField = clazz.getDeclaredField("level");
levelField.setAccessible(true);
levelField.set(user, 100);

反射也可以通过调用setter方法赋值:

final Class<User> clazz = User.class;
final Constructor<User> constructor = clazz.getConstructor();
final User user = constructor.newInstance();

final Method setUsernameMethod = clazz.getMethod("setUsername", String.class);
setUsernameMethod.invoke(user, "看山");
final Method setLevelMethod = clazz.getMethod("setLevel", int.class);
setLevelMethod.invoke(user, 100);

使用内省赋值:

final BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
final User user = new User();

final PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor prop : props) {
    if ("username".equals(prop.getName())) {
        final Method method = prop.getWriteMethod();
        method.invoke(user, "看山");
    } else if ("level".equals(prop.getName())) {
        final Method method = prop.getWriteMethod();
        method.invoke(user, 100);
    }
}

内省方式也可以直接指定属性:

final User user = new User();

final PropertyDescriptor usernameProp = new PropertyDescriptor("username", User.class);
final Method usernameWriteMethod = usernameProp.getWriteMethod();
usernameWriteMethod.invoke(user, "看山");

final PropertyDescriptor levelProp = new PropertyDescriptor("level", User.class);
final Method levelWriteMethod = levelProp.getWriteMethod();
levelWriteMethod.invoke(user, 100);

好了,基准测试的几种情况已经准备好了,为了达到更充分的验证,我们分别循环执行10、100、200 、500次,我们跑一下基准测试看看效果。

测试效果

保留下500次循环的数据(回复:Java可以获取源码)

Benchmark                                                           Score        Error    
BeanSetJmhTest.testBase                                           671.299 ±     14.201    基准
BeanSetJmhTest.testAccessFieldCacheByReflectField                6451.184 ±    212.541    反射-缓存-属性赋值
BeanSetJmhTest.testMethodCacheByReflect                         13381.968 ±   1921.017    反射-缓存-方法赋值
BeanSetJmhTest.testMethodCacheByIntrospector                    13523.807 ±   2146.288    内省-缓存-方法赋值
BeanSetJmhTest.testMethodByReflect                              44874.497 ±  14215.009    反射-方法赋值
BeanSetJmhTest.testAccessFieldByReflect                         57989.549 ± 282731.822    反射-属性赋值
BeanSetJmhTest.testAccessFieldCacheByIntrospectorDirectProp    121879.007 ±  28027.596    内省-缓存-指定属性赋值
BeanSetJmhTest.testAccessFieldCacheByIntrospectorProps         167602.264 ±  30272.412    内省-缓存-属性循环赋值
BeanSetJmhTest.testAccessFieldByIntrospectorProps              204765.110 ±  53973.520    内省-属性循环赋值
BeanSetJmhTest.testAccessFieldByIntrospectorDirectProp         783250.528 ±  40212.597    内省-指定属性赋值

可视化结果:

基准测试结果基准测试结果

从结果看:

  1. 在设置属性方面,反射性能优于内省;【上面结果是在JDK21测试的,试过JDK8、JDK17结果相似,不太确定有些文章说的内省性能优于反射是怎么测试的。】;
  2. 有缓存的逻辑性能会明显优于没有缓存的逻辑,无论是反射还是内省;
  3. 非必要情况,不要使用反射和内省,直接用JavaBean的setter赋值,性能差的太多。
责任编辑:武晓燕 来源: 看山的小屋
相关推荐

2010-03-12 08:55:06

Java内省反射

2021-07-11 09:34:45

ArrayListLinkedList

2024-11-08 08:42:08

内省机制JavaBean描述器

2009-07-14 18:09:08

Jython的内省

2024-01-17 10:05:09

Python内省反射机制

2011-02-28 09:51:43

内省

2011-05-25 14:46:16

程序员

2011-09-27 10:23:24

Java反射机制

2010-03-10 18:42:30

Python性能

2017-09-12 15:30:31

2023-04-10 07:26:28

UseStateUseReducer

2022-06-24 09:41:37

制造业技能物联网

2011-07-01 15:04:49

Qt 内省

2010-05-07 17:50:31

Unix服务器

2009-02-03 09:42:53

JAVA类JVM指令forName方法

2023-07-05 14:38:09

2024-06-04 00:00:30

C#反射编程

2011-08-02 18:07:03

iPhone 内省 Cocoa

2010-09-26 09:20:39

JVM1.6JVM1.5

2022-04-28 08:52:40

懒加载Web
点赞
收藏

51CTO技术栈公众号