Java反射原理及简单的源码解析

前言

首先,了解下java类的初始化过程:

编程:将java文件编译为.class字节码文件

加载:类加载器负责根据一个类的全限定名来读取此类的二进制字节流到JVM内部,并存储在运行时内存区的方法区,然后将其转换为一个与目标类型对应的java.lang.Class对象实例

连接:细分三步

验证:格式(class文件规范) 语义(final类是否有子类) 操作

准备:静态变量赋初值和内存空间,final修饰的内存空间直接赋原值,此处不是用户指定的初值。

解析:符号引用转化为直接引用,分配地址

初始化:有父类先初始化父类,然后初始化自己;将static修饰代码执行一遍,如果是静态变量,则用用户指定值覆盖原有初值;如果是代码块,则执行一遍操作。

原理

Java的反射就是利用上面第二步加载到jvm中的.class文件来进行操作的。.class文件中包含java类的所有信息,当你不知道某个类具体信息时,可以使用反射获取class,然后进行各种操作。

我们从源码开始分析:

首先定一个Student学生类,如下:

package com.hpsyche.wangyi;/**
 * @author Hpsyche
 */
public class Student {
    private String name;public Student() {
    }public Student(String name) {
        this.name = name;
    }public String getName() {
        return name;
    }public void setName(String name) {
        this.name = name;
    }
}

再有一个反射类,如下:

package com.hpsyche.wangyi;import java.lang.reflect.InvocationTargetException;
/**
 * @author Hpsyche
 */
public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class c= Class.forName("com.hpsyche.wangyi.Student");
        Student s= (Student) c.newInstance();
        System.out.println(s.getName());
    }
}

编码成字节码文件后,javap反解析:

并未发现什么端倪,主要在#4 #5处,通过Class.newInstance()产生Object,并通过checkcast转换为Student类;

我们深入看下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 {
            return tmpConstructor.newInstance((Object[])null);
        } catch (InvocationTargetException e) {
            Unsafe.getUnsafe().throwException(e.getTargetException());
            // Not reached
            return null;
        }
    }

发现其方法获取一个空参的构造方法,赋值给了引用型的变量 final Constructor c,并最终赋予了tempConstructor,并使用tempConstructor生成出了一个对象。

首先,需要了解Constructor c如何得到,进一步深入源码:

private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
                                        int which) throws NoSuchMethodException
    {
        Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
        for (Constructor<T> constructor : constructors) {
            if (arrayContentsEq(parameterTypes,
                                constructor.getParameterTypes())) {
                return getReflectionFactory().copyConstructor(constructor);
            }
        }
        throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
    }

第一步,获取所有的构造函数(判不判断为public);

第二步,通过所有的构造函数,找到匹配的其中一个并返回;

第二步比较简单,这里主要讲下第一步,继续看privateGetDeclaredConstructors的源码:


    private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
        checkInitted();
        Constructor<T>[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
            if (res != null) return res;
        }
        // No cached value available; request value from VM
        if (isInterface()) {
            @SuppressWarnings("unchecked")
            Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
            res = temporaryRes;
        } else {
            res = getDeclaredConstructors0(publicOnly);
        }
        if (rd != null) {
            if (publicOnly) {
                rd.publicConstructors = res;
            } else {
                rd.declaredConstructors = res;
            }
        }
        return res;
    }
    private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
        checkInitted();
        Constructor<T>[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
            if (res != null) return res;
        }
        // No cached value available; request value from VM
        if (isInterface()) {
            @SuppressWarnings("unchecked")
            Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
            res = temporaryRes;
        } else {
            res = getDeclaredConstructors0(publicOnly);
        }
        if (rd != null) {
            if (publicOnly) {
                rd.publicConstructors = res;
            } else {
                rd.declaredConstructors = res;
            }
        }
        return res;
    }

主要代码解析:

判断是否接口,是的话创建一个构造函数,并返回;否则,进入getDeclaredConstructors0方法;

点击进入,发现getDeclaredConstructors0为native方法;

private native Constructor[] getDeclaredConstructors0(boolean publicOnly);
进入openjdk,发现此方法在Class.c中对应的结构体中methods数组中的某一项,且对应着JVM_GetClassDeclaredConstructors地址;

static JNINativeMethod methods[] = {
    ....
    {"getDeclaredConstructors0","(Z)[" CTR, (void *)&JVM_GetClassDeclaredConstructors},
    ....
};

具体的实现是在java启动加载类时,改变JVM_GetClassDeclaredConstructors的具体引用。

由此,我们的Constructor即可拿到构造函数了。

ConstructorAccessor
    @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();
        }
        @SuppressWarnings("unchecked")
        T inst = (T) ca.newInstance(initargs);
        return inst;
    }

主要原理是,先判断是否是重写方法,再使用ConstructorAccessor在实现netInstance的功能,其功能也是通过native方法实现的,在此不做赘述。

总结

Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。其通过jvm中的.class文件来进行操作,.class文件中包含java类的所有信息,可以使用反射获取class,然后进行各种操作。

总结:反射就是把java类中的各种成分映射成一个个的Java对象,并且可以进行操作。

发布了63 篇原创文章 · 获赞 29 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Hpsyche/article/details/102783456