JDK源码(十四):Class

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

在日常开发过程中,会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。比如JDBC链接:

Class.forName("com.mysql.cj.jdbc.Driver");

反射机制的相关类

Class代表类的实例,表示正在运行的Java应用程序中的类和接口。Class没有公共构造函数。相反,Class对象由Java虚拟机在加载类时自动构造,并通过调用类加载器中的defineClass方法来构造。

类名

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

在Class中有个静态代码块,此native方法表示向JVM注册本地方法。

private static native void registerNatives();
static {
    registerNatives();
}

forName(String className)

@CallerSensitive
public static Class<?> forName(String className)
                throws ClassNotFoundException {
	//返回调用这个方法的类对象
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

返回给定字符串名称的类或接口关联的类对象,@CallerSensitive为了防止通过构造双重反射来提升权限

T newInstance()

    @CallerSensitive
    public T newInstance()
        throws InstantiationException, IllegalAccessException
    {
        if (System.getSecurityManager() != null) {
			//检查是否允许访问成员。如果拒绝访问,则抛出SecurityException
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
        }

        // 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 = {};
				//先获得Constructor数组,拿到所有的构造,包括非public的
                final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
                // 禁用构造函数的可访问性检查
                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;
        int modifiers = tmpConstructor.getModifiers();
		//检查是否是public,如果是public,返回true
        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;
        }
    }

栗子:

public class Student implements Serializable {

    private static final long serialVersionUID = -1L;
    private String id;

    private String name;

    public Integer age;

    public Student(){}

    public Student(String id, String name) {
        this.id = id;
        this.name = name;
    }

    private int sum(int i, int j){
        return i + j;
    }

    public Student getStudent(int id){
        return this;
    }

    public Student getStudent(String name){
        return new Student();
    }

    public String getInfo(){
        return id + " " + name;
    }
}

Student student = Student.class.newInstance();

但是在jdk9以上,这个方法被弃用了,而使用下面的方法:

Student student = 
    Student.class.getDeclaredConstructor().newInstance()

getMethods()

    @CallerSensitive
    public Method[] getMethods() throws SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        return copyMethods(privateGetPublicMethods());
    }

返回一个数组,该数组包含Method对象,这些对象包含该class对象表示的类或接口的所有公共方法,包括由该类或接口声明的方法以及从父类和父接口继承的方法。里面调用了privateGetPublicMethods方法

private Method[] privateGetPublicMethods() {
        checkInitted();
        Method[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            res = rd.publicMethods;
            if (res != null) return res;
        }
        //没有可用的缓存值;递归计算值。从获取公共声明的方法开始
        MethodArray methods = new MethodArray();
        {
            Method[] tmp = privateGetDeclaredMethods(true);
            methods.addAll(tmp);
        }
		// 首先检查父接口,这样我们可以更容易地过滤掉最后从父类继承的具体实现。
        MethodArray inheritedMethods = new MethodArray();
        for (Class<?> i : getInterfaces()) {
            inheritedMethods.addInterfaceMethods(i.privateGetPublicMethods());
        }
        if (!isInterface()) { //如果不是接口
            Class<?> c = getSuperclass();//得到父类
            if (c != null) {
                MethodArray supers = new MethodArray();
				//父类中的public方法
                supers.addAll(c.privateGetPublicMethods());
                // 过滤掉任何接口方法的具体实现
                for (int i = 0; i < supers.length(); i++) {
                    Method m = supers.get(i);
                    if (m != null &&
                            !Modifier.isAbstract(m.getModifiers()) &&
                            !m.isDefault()) {
                        inheritedMethods.removeByNameAndDescriptor(m);
                    }
                }
                // 在父接口之前插入父类的继承方法以满足getMethod的搜索顺序
                supers.addAll(inheritedMethods);
                inheritedMethods = supers;
            }
        }
        // 从继承的方法中筛选出所有本地方法
        for (int i = 0; i < methods.length(); i++) {
            Method m = methods.get(i);
            inheritedMethods.removeByNameAndDescriptor(m);
        }
        methods.addAllIfNotPresent(inheritedMethods);
        methods.removeLessSpecifics();
        methods.compactAndTrim();
        res = methods.getArray();
        if (rd != null) {
            rd.publicMethods = res;
        }
        return res;
    }

与getMethods()方法对应的还有一个getDeclaredMethods(),这个方法返回一个Method对象数组,其中包含该Class对象表示的类或接口的所有已声明方法,包括public、protected、default(package)访问和private方法,但不包括继承的方法。

    @CallerSensitive
    public Method[] getDeclaredMethods() throws SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        return copyMethods(privateGetDeclaredMethods(false));
    }
    private Method[] privateGetDeclaredMethods(boolean publicOnly) {
        checkInitted();
        Method[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
            if (res != null) return res;
        }
		//getDeclaredMethods0底层方法获取本类方法
        res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
        if (rd != null) {
            if (publicOnly) {
                rd.declaredPublicMethods = res;
            } else {
                rd.declaredMethods = res;
            }
        }
        return res;
    }

getFields() 

@CallerSensitive
    public Field[] getFields() throws SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        return copyFields(privateGetPublicFields(null));
    }

返回一个包含Field对象的数组,该数组包含Class对象表示的类或接口的所有可访问公共字段。包括父类和父接口的公共字段。调用的privateGetPublicFields方法如下:

private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) {
        checkInitted();
        Field[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            res = rd.publicFields;
            if (res != null) return res;
        }
        List<Field> fields = new ArrayList<>();
        if (traversedInterfaces == null) {
            traversedInterfaces = new HashSet<>();
        }
        // 类本身的字段
        Field[] tmp = privateGetDeclaredFields(true);
        addAll(fields, tmp);
        // 遍历父接口
        for (Class<?> c : getInterfaces()) {
            if (!traversedInterfaces.contains(c)) {
                traversedInterfaces.add(c);
                addAll(fields, c.privateGetPublicFields(traversedInterfaces));
            }
        }
        // 父类
        if (!isInterface()) {
            Class<?> c = getSuperclass();
            if (c != null) {
                addAll(fields, c.privateGetPublicFields(traversedInterfaces));
            }
        }

        res = new Field[fields.size()];
        fields.toArray(res);
        if (rd != null) {
            rd.publicFields = res;
        }
        return res;
    }

getFields()也有一个对应的方法getDeclaredFields(),这个方法返回Field对象的数组,该数组包含该Class对象表示的类或接口声明的所有字段。这包括公共、受保护、默认(包)访问和私有字段,但不包括继承字段。

    @CallerSensitive
    public Field[] getDeclaredFields() throws SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        return copyFields(privateGetDeclaredFields(false));
    }
   private Field[] privateGetDeclaredFields(boolean publicOnly) {
        checkInitted();
        Field[] res;
        ReflectionData<T> rd = reflectionData();
        if (rd != null) {
            res = publicOnly ? rd.declaredPublicFields : rd.declaredFields;
            if (res != null) return res;
        }
        // 调用底层方法
        res = Reflection.filterFields(this, getDeclaredFields0(publicOnly));
        if (rd != null) {
            if (publicOnly) {
                rd.declaredPublicFields = res;
            } else {
                rd.declaredFields = res;
            }
        }
        return res;
    }

getResourceAsStream(String name)

public InputStream getResourceAsStream(String name) {
		//如果名称不是绝对的,则添加包名称前缀如果名称是绝对的,则删除前导“/”
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResourceAsStream(name);
        }
        return cl.getResourceAsStream(name);
    }

此方法查找具有给定名称的资源。搜索与给定类关联的资源的规则是通过定义类的ClassLoader来实现的。此方法委托给此对象的类加载器。如果此对象是由引导类加载器加载的,则方法将委托给getSystemResourceAsStream。如果name以'/'开头,则资源的绝对名称是'/'后面的部分。如果名称不是绝对的,则添加包名称前缀,如果名称是绝对的,则删除前导“/”。


InputStream resourceAsStream = 
                Student.class.getResourceAsStream("application.xml");

更多精彩内容请关注微信公众号:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章