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方法。

相关推荐
JavaGuide5 分钟前
一条 SQL 语句在 MySQL 中是如何执行的?
java·数据库·后端·mysql
阿华的代码王国14 分钟前
【JavaEE】——多线程(join阻塞,计算,引用,状态)
java·开发语言·数据结构·java-ee
江喜原19 分钟前
微服务下设计一个注解标识是否需要登录
java·微服务·架构·登录
ABin-阿斌25 分钟前
SpringBoot 整合 Easy_Trans 实现翻译的具体介绍
java·spring boot·后端
边疆.26 分钟前
数据结构:内部排序
c语言·开发语言·数据结构·算法·排序算法
菜鸟求带飞_28 分钟前
算法打卡:第十一章 图论part03
java·数据结构·算法·深度优先·图论
圆头圆脑圆JAVA28 分钟前
简单了解微服务--黑马(在更)
java·spring boot·微服务
木子欢儿35 分钟前
在 Debian 12 上安装 Java 21
java·运维·开发语言·debian
一二小选手38 分钟前
【高级编程】XML DOM4J解析XML文件(含案例)
xml·java
终末圆40 分钟前
MyBatis XML映射文件编写【后端 18】
xml·java·开发语言·后端·算法·spring·mybatis