java 各种方法反射性能对比(原生/Introspector/MethodHandles/MethodAccess)

直接上代码:

package com.example.demo;

import com.esotericsoftware.reflectasm.MethodAccess;
import lombok.Data;
import lombok.Getter;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import sun.reflect.MethodAccessor;

import java.beans.*;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;

public class DemoApplication {

    @Test
    public void reflect() throws Throwable {

        User user = new User();
        user.age="111";
        user.name = "bb";


        Instant st = Instant.now();
        for (int i = 0; i <10000000 ; i++) {
            Class clz = user.getClass();
            Method[] methods = clz.getMethods();
            for (int j = 0; j <methods.length-9 ; j++) {
                Method method = methods[j];
                try {
                        Object invoke = method.invoke(user);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("原生耗时"+ Duration.between(st,Instant.now()).toMillis());


        Instant st2 = Instant.now();
        for (int i = 0; i <10000000 ; i++) {
            BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass());

            for (PropertyDescriptor pdsc : beanInfo.getPropertyDescriptors()) {
                pdsc.getReadMethod().invoke(user);
            }
        }
        System.out.println("Introspector耗时"+ Duration.between(st2,Instant.now()).toMillis());


        Instant st3 = Instant.now();
        for (int i = 0; i <10000000 ; i++) {
            MethodHandles.Lookup lookup = MethodHandles.lookup();
            //方法类型表示接受的参数和返回类型(第一个参数是返回参数)
            MethodType  methodType  =  MethodType.methodType(Integer.TYPE);
//            MethodHandle id = lookup.findVirtual(user.getClass(), "getId", methodType);
            MethodHandle id = lookup.findVirtual(user.getClass(), "getId", methodType);
            id.invoke(user);

            MethodType  nMethodType  =  MethodType.methodType(String.class);
            MethodHandle name = lookup.findVirtual(user.getClass(), "getName", nMethodType);
            name.invoke(user);

            MethodType  agemethodType  =  MethodType.methodType(String.class);
            MethodHandle age = lookup.findVirtual(user.getClass(), "getAge", agemethodType);
            age.invoke(user);

            MethodType  sexmethodType  =  MethodType.methodType(Integer.TYPE);
            MethodHandle sex = lookup.findVirtual(user.getClass(), "getSex", sexmethodType);
            sex.invoke(user);

        }
        System.out.println("方法句柄耗时"+ Duration.between(st3,Instant.now()).toMillis());

        Instant st4 = Instant.now();
        for (int i = 0; i <10000000 ; i++) {

            MethodAccess methodAccessor = MethodAccess.get(user.getClass());
            Object id = methodAccessor.invoke(user, "getId",null);

            Object name = methodAccessor.invoke(user, "getName",null);

            Object age = methodAccessor.invoke(user, "getAge", null);

            Object sex = methodAccessor.invoke(user, "getSex", null);

        }
        System.out.println("字节码耗时"+ Duration.between(st4,Instant.now()).toMillis());

    }


    @Getter
    public static class User{

        private int id;
        public String name;
        public String age;
        private int sex;
    }

}

打印:

原生耗时5766
Introspector耗时5335
方法句柄耗时73953
字节码耗时33166

第二种方式测试:

package com.example.demo;

import com.esotericsoftware.reflectasm.MethodAccess;
import lombok.Getter;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;

public class ReflectTest {


    @Test
    public void reflect() throws Throwable {

        User user = new User();
        user.age="111";
        user.name = "bb";


        Instant st = Instant.now();
        for (int i = 0; i <10000000 ; i++) {
            Class clz = user.getClass();
            Method exec = clz.getMethod("exec", String.class);
            exec.invoke(user,"222");
        }
        System.out.println("原生耗时"+ Duration.between(st,Instant.now()).toMillis());


        Instant st2 = Instant.now();
        for (int i = 0; i <10000000 ; i++) {
            BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass());
            MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
            for (MethodDescriptor methodDescriptor : methodDescriptors) {
                Method method = methodDescriptor.getMethod();
                if(method.getName().equals("exec"))
                    method.invoke(user,"3333");
            }

        }
        System.out.println("Introspector耗时"+ Duration.between(st2,Instant.now()).toMillis());


        Instant st3 = Instant.now();
        for (int i = 0; i <10000000 ; i++) {
            MethodHandles.Lookup lookup = MethodHandles.lookup();
            //方法类型表示接受的参数和返回类型(第一个参数是返回参数)
            MethodType  methodType  =  MethodType.methodType(Void.TYPE,String.class);
            MethodHandle id = lookup.findVirtual(user.getClass(), "exec", methodType);
            id.invoke(user,"222");

        }
        System.out.println("方法句柄耗时"+ Duration.between(st3,Instant.now()).toMillis());

        Instant st4 = Instant.now();
        for (int i = 0; i <10000000 ; i++) {

            MethodAccess methodAccessor = MethodAccess.get(user.getClass());
            Object id = methodAccessor.invoke(user, "exec","aa");

        }
        System.out.println("字节码耗时"+ Duration.between(st4,Instant.now()).toMillis());

    }


    @Getter
    public static class User{

        private int id;
        public String name;
        public String age;
        private int sex;


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

}

打印:

原生耗时4784
Introspector耗时9276
方法句柄耗时17882
字节码耗时28180

解释说明:

以上代码可能有写法问题,与实际预期不相符。
个人预期:

  1. 字节快于=>Introspector快于=>方法句柄快于=>原生

官网说MethodHandles(方法句柄应该是高于原生反射的),字节码应该是最快的。

最终说明Introspector(逻辑中有缓存)始终是最快的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值