什么是反射

运行时动态获取对象的全部类型信息。

反射原理-Class类 + 类加载

在markword中保存有对象的类型指针,这个指针会指向Class对象,这个对象保存了类型信息,就是类加载的时候会将对应的类型定义读入到内存中,markword的类型指针会指向这个类的类型定义。

Java反射-LMLPHP

所以可以通过.class来获取对象的类型信息,然后通过Class来进行保存,访问对应的类。

另外加载是动态加载的,不是静态加载的。不是一次性将所有的class读入到内存中,而是在发现缺少某一个class的时候,再把对应的类型定义读入到内存中。

反射的常用接口

  1. .classs
  2. .getClass
  3. Class.forName(“全类名”);
  4. class.newInstance();
  1. getMethod(name,参数类型)。通过invoke(对象,参数)进行调用,静态方法使用invoke(null, 参数)
  2. 非public方法,使用setAccessible(true);调用
  3. 仍旧遵循堕胎原则
  1. Field getField(name):根据字段名获取某个 public 的 field(包括父类)
  2. Field getDeclaredField(name):根据字段名获取当前类的某个 field(不包括父类)
  3. Field[] getFields():获取所有 public 的 field(包括父类)
  4. Field[] getDeclaredFields():获取当前类的所有 field(不包括父类)

父类的字段无法继承,如果想要获取父类的方法,需要通过不加declared进行访问。

反射的安全性

由于可以通过setAccessible(true)访问私有属性、方法,所以需要进行保证。一般是使用SecurityManager进行访问性的保证。可以自定义用户的SecurityManager,通过继承的方式。下面是一个例子。

  1. 方法一:继承securityManger
  2. 方法二:指定安全策略文件,然后通过System.setProperty(”java.security.policy“, 路径); System.setSecurityManager(new SecurityManager());进行保证

方法一:

import java.lang.reflect.ReflectPermission;

public class SecurityManagerExample {

    public static void main(String[] args) {
        // 创建自定义的安全管理器
        SecurityManager securityManager = new CustomSecurityManager();

        // 设置自定义的安全管理器
        System.setSecurityManager(securityManager);

        // 尝试进行反射操作
        try {
            // 获取Class对象
            Class<?> clazz = MyClass.class;

            // 通过反射调用私有方法
            clazz.getDeclaredMethod("privateMethod").invoke(new MyClass());
        } catch (Exception e) {
            System.out.println("Security exception: " + e.getMessage());
        }
    }

    static class CustomSecurityManager extends SecurityManager {
        @Override
        public void checkPermission(java.security.Permission perm) {
            // 检查反射相关的权限
            if (perm instanceof ReflectPermission) {
                String name = perm.getName();
                if (name != null && name.startsWith("suppressAccessChecks")) {
                    throw new SecurityException("Reflective access is not allowed.");
                }
            }
        }
    }

    static class MyClass {
        private void privateMethod() {
            System.out.println("This is a private method.");
        }
    }
}

方法二:

grant {
    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
import java.lang.reflect.Method;

public class SecurityPolicyExample {

    public static void main(String[] args) {
        // 设置安全策略文件路径
        System.setProperty("java.security.policy", "path/to/mysecurity.policy");

        // 启用安全管理器
        System.setSecurityManager(new SecurityManager());

        // 尝试进行反射操作
        try {
            // 获取Class对象
            Class<?> clazz = MyClass.class;

            // 通过反射调用私有方法
            Method privateMethod = clazz.getDeclaredMethod("privateMethod");
            privateMethod.setAccessible(true);
            privateMethod.invoke(new MyClass());
        } catch (Exception e) {
            System.out.println("Security exception: " + e.getMessage());
        }
    }

    static class MyClass {
        private void privateMethod() {
            System.out.println("This is a private method.");
        }
    }
}

动态代理

在运行期间创建某一个接口的实例。

原理就是在运行期间动态创建class字节码并加载的过程

使用proxy创建代理对象,将接口方法代理给InvokeHandler完成的。

动态代理原理是反射。InvokeHandler的调用使用了反射的.class.getMethod方法。

11-07 13:19