千家信息网

怎么理解序列化中的反射

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,本篇内容主要讲解"怎么理解序列化中的反射",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么理解序列化中的反射"吧!前言序列化大家都不陌生,说白了就是把当前
千家信息网最后更新 2026年11月02日怎么理解序列化中的反射

本篇内容主要讲解"怎么理解序列化中的反射",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"怎么理解序列化中的反射"吧!

前言

序列化大家都不陌生,说白了就是把当前类对象的状态保存为二进制,然后被用来持久化或者网络传输;常用的RPC框架在数据传输前都会进行序列化操作,主流的RPC框架包含了多种序列化方式比如protobuf,fastjson,kryo,hessian,java内置序列化等等,大致可以分为二进制和字符串(json字符串)。

反射

因为需要把当前类对象状态保存为二进制,所以往往需要获取所有类属性,这时候大部分的序列化方式都用到了反射,通过反射获取所有类属性获取方法,然后获取到属性值,大致如下:

//1.方法Method[] methods = obj.getClass().getDeclaredMethods();for(Method method : methods) {    method.invoke(obj);}//2.字段Field fields[] = obj.getClass().getDeclaredFields();for (Field field : fields) {    field.get(obj);}

但是反射往往在性能上被大家所怀疑,所以出现了类似protobuf采用自动生成序列化代码的方式,fastjson使用ASM代替反射的方式;下面我们先用简单的测试来对比一下各种方式的性能,看反射是否真的慢;

性能测试

在windows10+jdk8环境下分别对直接,反射,以及ASM调用方法分别进行压力测试,看起消耗的时间,测试中可以多次执行,取稳定的值;以下测试分别从Person对象通过方法获取属性值,如下:

public class Person {private String id;private String name;    public String getId() {return id;    }public String getName() {return name;    }}

直接调用

直接调用也就是我们平时最常用的方式,直接通过对象调用方法名称获取属性值,我们在压测的时候会分别轮询两个方法:

public static void test() {    Person person = new Person("10001", "zhaohui");long startTime = System.currentTimeMillis();for (int i = 0; i < 1_0000_0000; i++) {if (i % 2 == 0) {            person.getId();        } else {            person.getName();        }    }long endTime = System.currentTimeMillis();    System.out.println("Manual time:" + (endTime - startTime) + "ms");    }

多次测试结果大概在90ms左右,直接调用速度是最快的,但是需要我们手动的写每个bean的序列化代码,或者像protobuf一样使用工具给我们生成所有的序列化代码,比如生成Person的序列化代码:

 public void writeTo(com.google.protobuf.CodedOutputStream output)throws java.io.IOException {getSerializedSize();if (((bitField0_ & 0x00000001) == 0x00000001)) {      output.writeInt32(1, id_);    }if (((bitField0_ & 0x00000002) == 0x00000002)) {      output.writeBytes(2, getNameBytes());    }getUnknownFields().writeTo(output); }

可以看到每个生成的bean都自动生成了序列化代码,并且所有的bean都继承于统一的抽象类,这样提供一整套规范;有个缺点就是每次修改需要手动改proto文件,然后重新生成代码;

反射调用

使用jdk提供的反射机制,获取Methods,然后获取属性值,具体代码如下:

    public static void test() throws Exception {long startTime = System.currentTimeMillis();        Person person = new Person("10001", "zhaohui");        Method[] ms = Person.class.getDeclaredMethods();for (int i = 0; i < 1_0000_0000; i++) {            ms[i & ms.length - 1].invoke(person);        }long endTime = System.currentTimeMillis();        System.out.println("Reflex time:" + (endTime - startTime) + "ms");    }

经测试时间大概维持在205ms左右,和直接调用还是存在一定差距的,不过jdk每一轮的升级,都在提升性能,比如jdk7中引入的MethodHandle,模拟字节码层面的调用;

ASM调用

反射是读取持久堆上存储的类信息,而ASM是直接处理.class字节码的,无需加载类,我们这里使用ReflectASM来进行测试;

ReflectASM 是一个非常小的 Java 类库,通过代码生成来提供高性能的反射处理,自动为 get/set 字段提供访问类,访问类使用字节码操作而不是 Java 的反射技术,因此非常快。
    public static void test() {        Person person = new Person("10001", "zhaohui");long startTime = System.currentTimeMillis();        MethodAccess methodAccess = MethodAccess.get(Person.class);        String[] mns = methodAccess.getMethodNames();int len = mns.length;int indexs[] = new int[len];for (int i = 0; i < len; i++) {            indexs[i] = methodAccess.getIndex(mns[i]);        }for (int i = 0; i < 1_0000_0000; i++) {            methodAccess.invoke(person, indexs[i & len - 1]);        }long endTime = System.currentTimeMillis();        System.out.println("ASM time:" + (endTime - startTime) + "ms");    }

经测试时间维持在110ms左右,速度还是很快的,快赶上直接调用了;其中为了获得最大性能,应使用方法或字段索引而不是名称;

总结

可以看到虽然反射性能一直在提升,但是相比直接调用和ASM的方式还是有一点差距;但其实如果用在RPC上这点时间在整个网络传输上来说可以说微乎其微;如果对性能极度追求,可以考虑使用直接调用或者ASM的方式;

思考

关于直接调用上面说到protobuf,通过工具生成序列化代码,但是这种方式每次改动都要手动生成代码,有点麻烦,是否可以直接利用lombok这种框架做一个扩展,自动生成序列化代码,其实lombok底层也用到ASM,直接生成字节码代码,提供序列化注解

@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)public @interface Serialize {}

然后可以直接把注解应用到bean中,直接帮助我们生成序列化代码,就像@Getter/@Setter一样;相当于直接调用和ASM方式的一种整合;类似如下代码:

@Serializepublic class Person {private String id;private String name;    //自动生成public byte[] serialize(){        ByteBuffer bb = ByteBuffer.allocate(100);        bb.put(id.getBytes());        bb.put(name.getBytes());return bb.array();    }}

到此,相信大家对"怎么理解序列化中的反射"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

序列 反射 代码 生成 方式 测试 方法 性能 属性 字节 对象 时间 自动生成 二进制 字段 手动 框架 还是 传输 内容 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 朗新科技与工业互联网 世界互联网领先科技成果 互联网科技ppt模板 顺玮阁互联网科技 北京三清互联网科技 互联网科技产品 济南华为互联网科技产业总部基地 受益于互联网科技的高速发展 互联网金融中的现代科技 国大互联网教育科技有限公司工作 科技赋能视角下互联网保险发展 区块链结合互联网科技 互联网时代的科技公司 2021互联网科技公司排名 郑州欣桑互联网科技有限公司 万物互联网智能科技 互联网时代高科技布局 互联网金融金融科技 恒生科技互联网指数十大成分股 科技发展第三阶段互联网时代 中关村互联网科技集团 科技互联网公司装修 互联网科技上市公司 成都狮子座互联网科技 华服互联网科技官网 语蝶互联网科技有限公司 速维有品互联网信息科技(苏州)有限公司 扫呗互联网科技有限公司 吉林省码上互联网科技电话 互联网界的黑科技
0