jdk源码之Constructor

一、类图

Java resultfull get多参数可不传_构造函数

二、反射调用构造函数

两种:

  1. 调用无参构造函数:Class.newInstance()
  2. 调用带参数的构造函数:
    通过 Class 类获取 Constructor
    调用 Constructor 中的 newInstance(Object … initarges) 方法

其中Class.newInstance()最终调用的也是Constructor 的newInstance:

@CallerSensitive
    public T newInstance()
        throws InstantiationException, IllegalAccessException
    {
        if (System.getSecurityManager() != null) {
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
        }

        // NOTE: the following code may not be strictly correct under
        // the current Java memory model.

        // Constructor lookup
        if (cachedConstructor == null) {
            if (this == Class.class) {
                throw new IllegalAccessException(
                    "Can not call newInstance() on the Class for java.lang.Class"
                );
            }
            try {
                Class<?>[] empty = {};
                // 可以看到这边就会获得构造函数
                final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
                // Disable accessibility checks on the constructor
                // since we have to do the security check here anyway
                // (the stack depth is wrong for the Constructor's
                // security check to work)
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction<Void>() {
                        public Void run() {
                                c.setAccessible(true);
                                return null;
                            }
                        });
                // 将获得的构造函数存入缓存
                cachedConstructor = c;
            } catch (NoSuchMethodException e) {
                throw (InstantiationException)
                    new InstantiationException(getName()).initCause(e);
            }
        }
        // 得到构造函数
        Constructor<T> tmpConstructor = cachedConstructor;
        // Security check (same as in java.lang.reflect.Constructor)
        int modifiers = tmpConstructor.getModifiers();
        if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            if (newInstanceCallerCache != caller) {
                Reflection.ensureMemberAccess(caller, this, null, modifiers);
                newInstanceCallerCache = caller;
            }
        }
        // Run constructor
        try {
        	// 调用构造函数的newInstance方法获得实例
            return tmpConstructor.newInstance((Object[])null);
        } catch (InvocationTargetException e) {
            Unsafe.getUnsafe().throwException(e.getTargetException());
            // Not reached
            return null;
        }
    }

三、newInstance方法

  • 根据参数创建初始化实例,参数有匹配的规则;
  • 获取无参构造函数,参数长度可以为 0 或者 null;
  • 有访问权限并且对参数进行检查,需要获取到构造函数的声明类;
@CallerSensitive
    public T newInstance(Object ... initargs)
        throws InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException
    {
    	// 校验权限
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, null, modifiers);
            }
        }
        if ((clazz.getModifiers() & Modifier.ENUM) != 0)
            throw new IllegalArgumentException("Cannot reflectively create enum objects");
        // 获取构造函数的声明类
        ConstructorAccessor ca = constructorAccessor;   // read volatile
        if (ca == null) {
        	// 下面有方法详解
            ca = acquireConstructorAccessor();
        }
        //使用ConstructorAccessor创建实例
        @SuppressWarnings("unchecked")
        T inst = (T) ca.newInstance(initargs);
        return inst;
    }

acquireConstructorAccessor方法

private ConstructorAccessor acquireConstructorAccessor() {
        // First check to see if one has been created yet, and take it
        // if so.
        ConstructorAccessor tmp = null;
        // 如果root(private Constructor<T> root;)中保存了ConstructorAccessor 就直接返回
        if (root != null) tmp = root.getConstructorAccessor();
        if (tmp != null) {
            constructorAccessor = tmp;
        } else {
            // 否则就让反射工厂生成一个实例,并保存到root中并返回
            // 下面有方法详解
            tmp = reflectionFactory.newConstructorAccessor(this);
            setConstructorAccessor(tmp);
        }

        return tmp;
    }

来到ReflectionFactory中的newConstructorAccessor方法

public ConstructorAccessor newConstructorAccessor(Constructor<?> var1) {
    	// 检查是否初始化
    	// 下面有方法详解
        checkInitted();
        // 获得构造方法的类的实例
        Class var2 = var1.getDeclaringClass();
        // 校验实例是不是抽象类,如果是抽象类就抛出异常。
        if (Modifier.isAbstract(var2.getModifiers())) {
            return new InstantiationExceptionConstructorAccessorImpl((String)null);
        // 判断是否是 Class 实例,因为 Class 实例的构造函数是 private,所以这块也需要抛出异常。
        } else if (var2 == Class.class) {
            return new InstantiationExceptionConstructorAccessorImpl("Can not instantiate java.lang.Class");
        // 判断这个 Class 实例是否继承 ConstructorAccessorImpl,如果是父子关系,
        // 就调用 BootstrapConstructorAccessorImpl 创建 ConstructorAccessor,
        // 这个方法是调用 native 方法,底层用 c++ 实现的本地接口。
        } else if (Reflection.isSubclassOf(var2, ConstructorAccessorImpl.class)) {
            return new BootstrapConstructorAccessorImpl(var1);
        // 如果 noInflation 为 true 并且 实例不是匿名的,就是用Java 字节码存取器。
        // 需要调用 MethodAccessorGenerator.generateConstructor() 创建 ConstructorAccessor,
        // 原理是通过读取二进制文件,将 Class 实例加载进来,然后根据一些条件获取到想要的 Constructor。
        } else if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
            return (new MethodAccessorGenerator()).generateConstructor(var1.getDeclaringClass(), var1.getParameterTypes(), var1.getExceptionTypes(), var1.getModifiers());
        //上面的条件都不满足,就调用 NativeConstructorAccessorImpl
        } else {
        	// 下面有方法详解
            NativeConstructorAccessorImpl var3 = new NativeConstructorAccessorImpl(var1);
            DelegatingConstructorAccessorImpl var4 = new DelegatingConstructorAccessorImpl(var3);
            var3.setParent(var4);
            return var4;
        }
    }

来到checkInitted方法

private static void checkInitted() {
		// (initted记录是否被初始化),如果是false,就进行初始化并将initted改为true
        if (!initted) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    if (System.out == null) {
                        return null;
                    } else {
                    	// 从系统属性读取noInflation属性,默认值为false (private static boolean noInflation = false;)
                    	// 其中系可以通过 -D= 来设置系统属性,通过 System.getProperty("属性名称") 来获取属性值。
                    	// 如果设为true,就强制使用 Java 字节码存取器
                        String var1 = System.getProperty("sun.reflect.noInflation");
                        if (var1 != null && var1.equals("true")) {
                            ReflectionFactory.noInflation = true;
                        }
						// 从系统属性读取inflationThreshold,作用是定义JNI 存取器的使用次数的阈值
						// 默认值为15(private static int inflationThreshold = 15;)
						// JVM 访问反射的类的信息会先从 JNI 存取器读取 15(如果不修改默认值)次之后才会使用 Java 字节码存取器
                        var1 = System.getProperty("sun.reflect.inflationThreshold");
                        if (var1 != null) {
                            try {
                                ReflectionFactory.inflationThreshold = Integer.parseInt(var1);
                            } catch (NumberFormatException var3) {
                                throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", var3);
                            }
                        }

                        ReflectionFactory.initted = true;
                        return null;
                    }
                }
            });
        }
    }

JVM 有两种方法来访问有关反射的类的信息,可以使用 JNI (JNI(Java Native Interface),通过使用 Java 本地接口书写程序,可以确保代码在不同的平台上方便移植。)读取器或者 Java 字节码存取器。inflationThreshold 是使用 JNI 存取器的次数,值为 0 表示永不从 JNI 存取器读取。如果想强制使用 Java 字节码存取器,可以设置 noInflation 为 true。