Java反射

什么是反射

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

反射原理-Class类 + 类加载

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

所以可以通过.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());进行保证

方法一:

java 复制代码
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.");
        }
    }
}

方法二:

java 复制代码
grant {
    permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
java 复制代码
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方法。

相关推荐
汤米粥2 分钟前
小皮PHP连接数据库提示could not find driver
开发语言·php
冰淇淋烤布蕾5 分钟前
EasyExcel使用
java·开发语言·excel
拾荒的小海螺12 分钟前
JAVA:探索 EasyExcel 的技术指南
java·开发语言
Jakarta EE28 分钟前
正确使用primefaces的process和update
java·primefaces·jakarta ee
马剑威(威哥爱编程)36 分钟前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
白-胖-子1 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
好睡凯1 小时前
c++写一个死锁并且自己解锁
开发语言·c++·算法
java—大象1 小时前
基于java+springboot+layui的流浪动物交流信息平台设计实现
java·开发语言·spring boot·layui·课程设计
yyqzjw1 小时前
【qt】控件篇(Enable|geometry)
开发语言·qt
csdn_kike1 小时前
QT Unknown module(s) in QT 以及maintenance tool的更详细用法(qt6.6.0)
开发语言·qt