• java魔法类之ReflectionFactory介绍


    前言

    在看objenesis(一个提供多种实例化对象的方式的库)的源码时,发现其中使用到了ReflectionFactory类,通过它可以绕过构造器来实例化对象。

    简单使用

    定义一个包含有参构造器的类

    public class User {
    
      private String name;
    
      public User(String name) {
        System.out.println("User.Constructor");
      }
    
      @Override
      public String toString() {
        return "User.toString()";
      }
    }
    

    使用反射实例化对象

    import java.lang.reflect.Constructor;
    
    public class TestReflection {
    
      public static void main(String[] args) throws Exception {
        Constructor<User> declaredConstructor = User.class.getDeclaredConstructor();
        System.out.println(declaredConstructor.newInstance());
      }
    
    }
    

    会报错,因为没有无参的构造器

    Exception in thread "main" java.lang.NoSuchMethodException: com.imooc.sourcecode.java.objenesis.test1.User.<init>()
    	at java.base/java.lang.Class.getConstructor0(Class.java:3350)
    	at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2554)
    	at com.imooc.sourcecode.java.objenesis.test1.TestReflection.main(TestReflection.java:9)
    

    使用ReflectionFactory实例化对象

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import sun.reflect.ReflectionFactory;
    
    public class TestReflectionFactory {
    
      public static void main(String[] args)
          throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取ReflectionFactory对象,它本身是单例的
        ReflectionFactory reflectionFactory = ReflectionFactory.getReflectionFactory();
        //获取Object类的构造器
        Constructor<Object> constructor = Object.class.getDeclaredConstructor();
        //根据Object构造器创建一个User类的构造器
        Constructor<?> constructorForSerialization = reflectionFactory
            .newConstructorForSerialization(User.class, constructor);
        constructorForSerialization.setAccessible(true);
        //实例化对象
        System.out.println(constructorForSerialization.newInstance());
      }
    
    }
    

    输出结果为

    User.toString()
    

    可以看到正常实例化了对象并且没有执行构造器。

    实现原理

    内部使用字节码创建ConstructorAccessor接口的实现类

    public final Constructor<?> newConstructorForSerialization(Class<?> cl,
                                                                   Constructor<?> constructorToCall)
        {
            if (constructorToCall.getDeclaringClass() == cl) {
                constructorToCall.setAccessible(true);
                return constructorToCall;
            }
            return generateConstructor(cl, constructorToCall);
        }
    
    // 创建构造器
    private final Constructor<?> generateConstructor(Class<?> cl,
                                                         Constructor<?> constructorToCall) {
    
    	//核心逻辑,通过字节码生成ConstructorAccessor,实现类类型为SerializationConstructorAccessorImpl 
            ConstructorAccessor acc = new MethodAccessorGenerator().
                generateSerializationConstructor(cl,
                                                 constructorToCall.getParameterTypes(),
                                                 constructorToCall.getExceptionTypes(),
                                                 constructorToCall.getModifiers(),
                                                 constructorToCall.getDeclaringClass());
            Constructor<?> c = newConstructor(constructorToCall.getDeclaringClass(),
                                              constructorToCall.getParameterTypes(),
                                              constructorToCall.getExceptionTypes(),
                                              constructorToCall.getModifiers(),
                                              langReflectAccess().
                                              getConstructorSlot(constructorToCall),
                                              langReflectAccess().
                                              getConstructorSignature(constructorToCall),
                                              langReflectAccess().
                                              getConstructorAnnotations(constructorToCall),
                                              langReflectAccess().
                                              getConstructorParameterAnnotations(constructorToCall));
            setConstructorAccessor(c, acc);
            c.setAccessible(true);
            return c;
        }
    

    生成字节码的核心为MethodAccessorGenerator的generateSerializationConstructor()方法。

    参考

    objenesis官网
    reflectionFactory.newConstructorForSerialization原理

  • 相关阅读:
    DatePicker 日期选择器 split-panels 数组的时候,清空这个费劲啊,最后走的后门
    英语音标总结
    前台发布地址动态获取 本机地址
    SecureCRT windows 登录 linux
    The History of the English language 英语语音的起源
    iview 部分表单验证
    iView 表单验证 如果prop字段和表单里的字段对不上,会触发校验,提示错误信息
    hdu4370 0 or 1
    即时通讯上手必备知识点
    不使用Math.random实现随机数。
  • 原文地址:https://www.cnblogs.com/strongmore/p/15470175.html
Copyright © 2020-2023  润新知