🕖 反射

吞佛童子2022年10月10日
  • Java
  • Reflection
大约 5 分钟

🕖 反射

1. 作用

  • 获取任意一个类的 属性 & 方法 等

2. 获取 Class 对象的方式

1) 类名.class

Class b = ClassA.class;

2) Class.forName(...)

  • 调用 native 方法实现类的加载
    • 类加载 过程中的 加载、验证、解析、初始化 过程均会执行
  • 在 JDBC 编程中,我们通常采用 Class.forName ("com.mysql.jdbc.Driver"); 实现类的加载,而非 ClassLoader.loadClass(...),原因在于:
    • 我们需要通过该方法实现 类加载 过程中的 初始化操作,即执行 static 代码块 或 类静态变量的赋值 相关操作
package com.mysql.jdbc;
public class Driver extends com.mysql.cj.jdbc.Driver {
    public Driver() throws SQLException {
        super();
    }

    static {
        System.err.println("Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. "
                + "The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.");
    }
}

package com.mysql.cj.jdbc;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    static { // 向 DriverManager 注册本类
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

3) Object.getClass()

4) ClassLoader.loadClass(...)

  • 对应 JVM 过程中的 类加载 阶段中的 加载
    • 即,将二进制字节流加载到 内存中
    • 后续的 验证、准备、解析、初始化等操作均不会执行,需要 new() 时才进行

3. 反射常见方法

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
    // 创建此 Class 对象表示的类的新实例
    // 如果尚未初始化该类,则将其初始化。
    @CallerSensitive
    public T newInstance() throws InstantiationException, IllegalAccessException
    {
        if (System.getSecurityManager() != null) {
            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 = {};
                // 获取构造器
                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();
        if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
            Class<?> caller = Reflection.getCallerClass();
            if (newInstanceCallerCache != caller) {
                Reflection.ensureMemberAccess(caller, this, null, modifiers);
                newInstanceCallerCache = caller;
            }
        }
        // 通过 类构造器 生成 新实例
        try {
            return tmpConstructor.newInstance((Object[])null);
        } catch (InvocationTargetException e) {
            Unsafe.getUnsafe().throwException(e.getTargetException());
            return null;
        }
    }
    
    // --------------- 构造函数 ----------------------
    // 这包括 public、protected、default、private 构造函数
    // 如果该类具有默认构造函数,则它包含在返回的数组中。
    // 如果此 Class 对象表示接口、原始类型、数组类或 void,则此方法返回长度为 0 的数组。
    @CallerSensitive
    public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        return copyConstructors(privateGetDeclaredConstructors(false));
    }
    
    // --------------- 字段 ---------------------
    // 获取 类的所有 public 属性
    @CallerSensitive
    public Field[] getFields() throws SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        return copyFields(privateGetPublicFields(null));
    }
    
    // 返回一个 Field 对象数组,反映由此 Class 对象表示的类或接口声明的所有字段。
    // 这包括 public、protected、default、private,但不包括继承的字段
    @CallerSensitive
    public Field[] getDeclaredFields() throws SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        return copyFields(privateGetDeclaredFields(false));
    }
    
    // name 参数是一个字符串,它指定所需字段的简单名称
    @CallerSensitive
    public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        Field field = searchFields(privateGetDeclaredFields(false), name);
        if (field == null) {
            throw new NoSuchFieldException(name);
        }
        return field;
    }
    
    // ---------------- 方法 --------------
    // 返回一个包含 Method 对象的数组
    // 这包括 public、protected、default、private,但不包括继承的方法
    // 如果此 Class 对象表示具有多个已声明的具有相同名称和参数类型但返回类型不同的方法的类型,则返回的数组对于每个此类方法都有一个 Method 对象。
    @CallerSensitive
    public Method[] getDeclaredMethods() throws SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        return copyMethods(privateGetDeclaredMethods(false));
    }

    // name 参数是一个字符串,它指定所需方法的简单名称,
    // parameterTypes 参数是一个 Class 对象数组,这些对象按照声明的顺序标识方法的形式参数类型。
    // 如果在一个类中声明了多个具有相同参数类型的方法,并且其中一个方法的返回类型比其他任何方法都更具体,则返回该方法;否则任意选择其中一种方法
    @CallerSensitive
    public Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
        if (method == null) {
            throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
        }
        return method;
    }
}
上次编辑于: 2022/10/10 下午8:43:48
贡献者: liuxianzhishou