java源码分析-反射Class类

java源码分析-反射Class类

1.Class类是什么

​ Class本质上也是java的一个类,这个类是对java所有的类的相关信息进行提取和抽象。简单说,Class类就表示创建类的类型信息。Class类的对象能够在允许时提供某个类对象的类型信息,包含了对构造函数、方法、变量等一系列操作。

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement 

2.如何得到Class对象

获取一个类的Class对象有三种方式。

2.1getClass()方法

通过对象实例的getClass()方法,可以获取到Class对象。

public final native Class<?> getClass();

这是Object类中的一个native本地方法。

ClassDemo classDemo = new ClassDemo();
Class clazz = classDemo.getClass();
System.out.println(clazz);

2.2class属性

通过类的class属性可以获取到Class对象。

Class clazz1 = ClassDemo.class;
System.out.println(clazz1);

2.3通过Class的forName()方法

public static Class<?> forName(String className)
                throws ClassNotFoundException
 Class clazz2 = Class.forName("test.java.lang.reflect.ClassDemo");
 System.out.println(clazz2);

3.Class常用方法

3.1获取构造函数对象

(1)getDeclaredConstructors()

获取某个类所有的构造函数,包括私有构造函数和公共构造函数。

public Constructor<?>[] getDeclaredConstructors() throws SecurityException

(2)getConstructors()

获取某个类的公共构造函数。

public Constructor<?>[] getConstructors() throws SecurityExceptionp

(3)getConstructor(…)

根据参数列表类型获取某个类的指定构造函数。

public Constructor<T> getConstructor(Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException

测试:

定义一个ClassDemo类:

public class ClassDemo extends ClassDemoPareson implements IClassDemo {


    public ClassDemo() {
    }

    public static final Integer MIN = 0;

    public String age;

    private String name;

    public ClassDemo(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public int getNum() {
        return 0;
    }

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

    private String test(String arg){
        return null;
    }
}    

测试类:

package test.java.lang.reflect;

import java.lang.reflect.Constructor;
import java.util.Arrays;

public class ClassTest {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//        ClassDemo classDemo = new ClassDemo();
//        Class clazz = classDemo.getClass();
//        System.out.println(clazz);
//        Class clazz1 = ClassDemo.class;
//        System.out.println(clazz1);
//        Class clazz2 = Class.forName("test.java.lang.reflect.ClassDemo");
//        System.out.println(clazz2);
        ClassDemo classDemo = new ClassDemo();
        Class clazz = classDemo.getClass();
        Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
        System.out.println(Arrays.toString(declaredConstructors));
        Constructor[] constructors = clazz.getConstructors();
        System.out.println(Arrays.toString(constructors));
        Constructor constructor = clazz.getConstructor(String.class);
        System.out.println(constructor);
    }
}

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fcHz53tM-1611389093187)(C:\Users\viruser.v-desktop\AppData\Roaming\Typora\typora-user-images\image-20210122102520963.png)]![image-2021012213465037

3.2获取成员方法对象

(1)getDeclaredMethods()

​ 获取某个类定义的所有方法对象,包括私有方法、公共方法和静态方法。

public Method[] getDeclaredMethods() throws SecurityException

(2)getMethods()

获取所有的公共方法对象。

public Method[] getMethods() throws SecurityException

(3)getMethod(…)

根据方法名和参数列表获取指定的方法Method对象。

public Method getMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException

测试:

Method[] declaredMethods = clazz.getDeclaredMethods();
System.out.println(Arrays.toString(declaredMethods));
Method[] methods = clazz.getMethods();
System.out.println(Arrays.toString(methods));
Method setNameMethod = clazz.getMethod("setName", String.class);
System.out.println(setNameMethod);

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y0zf99Wh-1611389093188)(C:\Users\viruser.v-desktop\AppData\Roaming\Typora\typora-user-images\image-20210122104859435.png)]

3.3获取成员变量对象

(1)getDeclaredFields()

获取所有的成员变量Field对象,包括私有的、公共的和静态的。

public Field[] getDeclaredFields() throws SecurityException

(2)getFields()

获取公共的成员变量对象

public Field[] getFields() throws SecurityException

(3)getDeclaredField(…)

根据变量名称获取变量对象。

public Field getDeclaredField(String name)
        throws NoSuchFieldException, SecurityException

测试:

Field[] declaredFields = clazz.getDeclaredFields();
System.out.println(Arrays.toString(declaredFields));
Field[] fields = clazz.getFields();
System.out.println(Arrays.toString(fields));
Field name = clazz.getDeclaredField("name");
System.out.println(name);

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hLywAfv6-1611389093190)(C:\Users\viruser.v-desktop\AppData\Roaming\Typora\typora-user-images\image-20210122111418743.png)]

3.4其他方法

(1)getModifiers()

获取某个类的语言修饰符的整数值。

java语言描述符包括:

  • 可访问描述符:

    ​ private、public、protected、默认

  • 不可访问描述符

    ​ static、final、abstract、synchronized、volatile…

每一个描述符都对应着一个整数值。其具体的值在java.lang.reflect.Modifier类中有定义。

 /**
     * The {@code int} value representing the {@code public}
     * modifier.
     */
    public static final int PUBLIC           = 0x00000001;

    /**
     * The {@code int} value representing the {@code private}
     * modifier.
     */
    public static final int PRIVATE          = 0x00000002;

    /**
     * The {@code int} value representing the {@code protected}
     * modifier.
     */
    public static final int PROTECTED        = 0x00000004;

    /**
     * The {@code int} value representing the {@code static}
     * modifier.
     */
    public static final int STATIC           = 0x00000008;

    /**
     * The {@code int} value representing the {@code final}
     * modifier.
     */
    public static final int FINAL            = 0x00000010;

    /**
     * The {@code int} value representing the {@code synchronized}
     * modifier.
     */
    public static final int SYNCHRONIZED     = 0x00000020;

    /**
     * The {@code int} value representing the {@code volatile}
     * modifier.
     */
    public static final int VOLATILE         = 0x00000040;

    /**
     * The {@code int} value representing the {@code transient}
     * modifier.
     */
    public static final int TRANSIENT        = 0x00000080;

    /**
     * The {@code int} value representing the {@code native}
     * modifier.
     */
    public static final int NATIVE           = 0x00000100;

    /**
     * The {@code int} value representing the {@code interface}
     * modifier.
     */
    public static final int INTERFACE        = 0x00000200;

    /**
     * The {@code int} value representing the {@code abstract}
     * modifier.
     */
    public static final int ABSTRACT         = 0x00000400;

    /**
     * The {@code int} value representing the {@code strictfp}
     * modifier.
     */
    public static final int STRICT           = 0x00000800;

    // Bits not (yet) exposed in the public API either because they
    // have different meanings for fields and methods and there is no
    // way to distinguish between the two in this class, or because
    // they are not Java programming language keywords
    static final int BRIDGE    = 0x00000040;
    static final int VARARGS   = 0x00000080;
    static final int SYNTHETIC = 0x00001000;
    static final int ANNOTATION  = 0x00002000;
    static final int ENUM      = 0x00004000;
    static final int MANDATED  = 0x00008000;

class.getModifiers()方法就是获取这个整数值。它是一个本地方法。

public native int getModifiers();

(2)isInterface()

判断这个类是否是接口。

public native boolean isInterface();

(3)getName()

获取类的全路径名。

public String getName()

(4)getSuperclass()

获取该类的父类类型Class。

public native Class<? super T> getSuperclass();	

测试:

int modifiers = clazz.getModifiers();
System.out.println(modifiers);
boolean anInterface = clazz.isInterface();
System.out.println(anInterface);
String clazzName = clazz.getName();
System.out.println(clazzName);
Class clazzSuperclass = clazz.getSuperclass();
System.out.println(clazzSuperclass);

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NDzwi2yp-1611389093193)(C:\Users\viruser.v-desktop\AppData\Roaming\Typora\typora-user-images\image-20210122113822658.png)]

还有很多其他的方法,这里就不一一举例了。

4.重点解析

下面我们针对以下几个方法重点看一下源码。

4.1getConstructors()方法

​ 前面说过getConstructors()是获取类的公共构造函数对象Constructor。

public Constructor<?>[] getConstructors() throws SecurityException {    //获取公共构造器public
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);//(1)
    return copyConstructors(privateGetDeclaredConstructors(true));//(2)
}

getConstructors主要分为两个部分,一个是校验成员权限,另一个是获取Constructor对象。

(1)校验权限

private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) {  //设置成员的访问权限
        final SecurityManager s = System.getSecurityManager();  //获取安全管理器,默认是关闭的,所以这里是null
        if (s != null) {
            /* Default policy allows access to all {@link Member#PUBLIC} members,
             * as well as access to classes that have the same class loader as the caller.
             * In all other cases, it requires RuntimePermission("accessDeclaredMembers")
             * permission.
             */
            final ClassLoader ccl = ClassLoader.getClassLoader(caller);//获取调用类的类加载器
            final ClassLoader cl = getClassLoader0();
            if (which != Member.PUBLIC) {   //如果不是public公共的访问标识符
                if (ccl != cl) {
                    s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);    //设置权限
                }
            }
            this.checkPackageAccess(ccl, checkProxyInterfaces); //设置包的访问权限
        }
    }

SecurityManager类:这是java安全管理器,允许应用程序实现安全策略。具体可看《java反射源码分析-SecurityManager》一片,有介绍。

简单来说这段代码就是来检查程序操作是否具有对应的权限,一般情况下默认是没有启动安全管理器的。

(2)获取Constructor对象

先看privateGetDeclaredConstructors()方法

private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {   //获取构造方法(有参和无参)
        checkInitted();// 1
        Constructor<T>[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {	//2
            res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
            if (res != null) return res;
        }
        // No cached value available; request value from VM
        if (isInterface()) {    //3
            @SuppressWarnings("unchecked")
            Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
            res = temporaryRes; 
        } else {	//4
            res = getDeclaredConstructors0(publicOnly);
        }
        if (rd != null) {	//5
            if (publicOnly) {
                rd.publicConstructors = res;
            } else {
                rd.declaredConstructors = res;
            }
        }
        return res;
    }

总结一下privateGetDeclaredConstructors()方法:

1)初始化校验,查看系统内部相关配置是否加载完成;

2)获取ReflectionData对象,该对象用于缓存constructor等相关数据;如果有缓存,则直接从缓存中获取对应的数据,并返回;

// Lazily create and cache ReflectionData
    private ReflectionData<T> reflectionData() {        //惰性创建和缓存反射的数据
        SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;  //使用软引用的方式来创建ReflectionData对象 //软引用:内存不足时会回收此对象
        int classRedefinedCount = this.classRedefinedCount; //设置重新定义的次数
        ReflectionData<T> rd;
        if (useCaches &&                                    //启用缓存
            reflectionData != null &&                       //软引用不为空
            (rd = reflectionData.get()) != null &&          //ReflectionData对象不为空
            rd.redefinedCount == classRedefinedCount) {     //redefinedCount值等于classRedefinedCount
            return rd;
        }
        // else no SoftReference or cleared SoftReference or stale ReflectionData
        // -> create and replace new instance
        return newReflectionData(reflectionData, classRedefinedCount);//否则新建缓存
    }

3)判断Class对象所表示的类是否是接口,如果是则返回一个空的Constructor数组对象,因为接口是没有构造函数的;

4)如果不是接口,则会通过本地方法getDeclaredConstructors0来获取构造函数;

private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);

5)将获取到的数据保存到缓存对象ReflectionData中。

获取到Constructor之后并没有直接返回给调用方,而是在通过拷贝的方式返回。具体看一下copyConstructors源码

private static <U> Constructor<U>[] copyConstructors(Constructor<U>[] arg) {//拷贝constructors
        Constructor<U>[] out = arg.clone();//获取Constructor副本
        ReflectionFactory fact = getReflectionFactory();    //获取获取反射工厂
        for (int i = 0; i < out.length; i++) {  
            out[i] = fact.copyConstructor(out[i]);//通过反射工厂拷贝Constructor
        }
        return out;
    }

可以看到,通过copyConstructors方法,将Constructors的拷贝副本返回该调用者。这样调用者对Constructor做的任何改变都不影响原本的Constructor。

4.2newInstance()方法

该方法也是Class对象的一个重要的方法,起作用就是根据class类型创建一个实例对象。

public T newInstance()
        throws InstantiationException, IllegalAccessException
    {   
        if (System.getSecurityManager() != null) {  //1
            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) {    //2
            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)) {	//3
            Class<?> caller = Reflection.getCallerClass();  
            if (newInstanceCallerCache != caller) { 
                Reflection.ensureMemberAccess(caller, this, null, modifiers);   
                newInstanceCallerCache = caller;
            }
        }
        // Run constructor
        try {
            return tmpConstructor.newInstance((Object[])null);  //4
        } catch (InvocationTargetException e) {
            Unsafe.getUnsafe().throwException(e.getTargetException());
            // Not reached
            return null;
        }
    }

我们将newInstance方法分为四个部分,主要的工作如下:

(1)根据SecurityManager判断校验权限;

(2)获取cachedConstructor缓存对象,调用getConstructor0方法获取构造函数,并放入缓存中,方便下一次直接获取;

(3)设置成员访问权限;

(4)调用构造函数Constructor对象的newInstance方法获取实例对象。

public T newInstance(Object ... initargs)
        throws InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException
    {   //通过参数列表,构造该构造器对应的类的实例对象
        if (!override) {//该标识表示是否覆盖语言级别的访问检查权限,初始false,可以通过通过constructor1.setAccessible(true)设置为true
            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);//通过构造函数声明类的newInstance来实例化对象
        return inst;
    }

至于ConstructorAccessor.newInstance()方法我们在《java反射源码分析-Constructor》中已经详细说明,这里就不再说了。

5.相关类

5.1ReflectionFactory

​ 通过类名我们就可以大致知道,这是一个工厂,用于反射的工厂类。通常的工厂都是用于实例化具体产品,担任着类的对象的创建工作,但是ReflectionFactory却有点不同,它是通过深度克隆的方式来创建发射的核心对象Field、Constructor和Method。并不是创建,而是复制一份。我们看一下他的三个克隆方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PdCI7NRL-1611389093194)(C:\Users\viruser.v-desktop\AppData\Roaming\Typora\typora-user-images\image-20210121200331931.png)]

那NewField()方法来看一下:

 public Field newField(Class<?> var1, String var2, Class<?> var3, int var4, int var5, String var6, byte[] var7) {
 	return langReflectAccess().newField(var1, var2, var3, var4, var5, var6, var7);	//通过LangReflectAccess调用newField方法
 }

 private static LangReflectAccess langReflectAccess() {	//获取LangReflectAccess
        if (langReflectAccess == null) {
            Modifier.isPublic(1);	//设置访问权限public
        }

        return langReflectAccess;
    }


调用ReflectAccess类来进行实例化Field。

public Field newField(Class<?> declaringClass,
                          String name,
                          Class<?> type,
                          int modifiers,
                          int slot,
                          String signature,
                          byte[] annotations)
    {
        return new Field(declaringClass,
                         name,
                         type,
                         modifiers,
                         slot,
                         signature,
                         annotations);
    }

也就是说通过反射工厂创建Field、Constructor和Method底层都是通过new的形式创建一个新的对应类型的实例。

5.2Reflection

Reflection类类似于一个工具类,提供了一些本地方法和用来校验相关成员权限的方法。

例如:

本地方法

@CallerSensitive
public static native Class<?> getCallerClass();//获取调用类的Class类型

校验成员权限

public static void ensureMemberAccess(Class<?> var0, Class<?> var1, Object var2, int var3) throws IllegalAccessException {
        if (var0 != null && var1 != null) {
            if (!verifyMemberAccess(var0, var1, var2, var3)) {
                throw new IllegalAccessException("Class " + var0.getName() + " can not access a member of class " + var1.getName() + " with modifiers \"" + Modifier.toString(var3) + "\"");
            }
        } else {
            throw new InternalError();
        }
    }

6.小结

​ 本章主要是对java反射机制中的核心类Class进行类分析,下面总结几点:

(1)想要通过反射对某个类或对象进行操作,首先需要获取这个类的Class对象;

(2)获取Class对象的方式有三种,分别是对象的getClass()方法,class属性和通过Class.forName()方法获取;

(3)得到了Class对象之后就可以获取到这个类所有信息了,并进行后续操作;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值