zoukankan      html  css  js  c++  java
  • 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原理

  • 相关阅读:
    学习 Ext 中一些不错的编码习惯
    actionbar tab字体颜色
    Android Library工程实现模块复用(代码及资源文件)
    Fragment之底部导航栏的实现
    actionbar修改背景颜色
    Android在桌面添加可拖动、点击的悬浮窗口
    请问GridView中 两个图片之间的间距是如何设置的
    http://www.55zm.com/a/20120702/38037.html
    android开源系列:CircleImageView自定义圆形控件的使用
    App版本更新时对SQLite数据库升级或者降级遇到的问题
  • 原文地址:https://www.cnblogs.com/strongmore/p/15470175.html
Copyright © 2011-2022 走看看