• Java安全初学之反射


    前言:

    复现fastjson的时候深深意识到了需要好好学习一下Java和Java安全,激情的学习了一番java安全中重要的几部分:反序列化、反射、rmi、动态代理,从反射开始做个总结。

    反射:java虚拟机在运行时获取获取类的结构信息并调用其方法和属性

    也就是说,反射机制和普通方式最大的区别是,普通方式(也就是我们通过正常的new对象)需要在编译时就找到和检查类的.class文件,而反射机制是在运行时做这一步骤。

    反射机制用到的类:
    Class:获取类的Class对象
    Constructor:通过指定参数创建对象
    Method:获取类的方法
    Filed: 获取类的属性
    Array:动态创建数组,访问数组元素

    反射代码举例:

    import java.lang.Class;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    //构造方法为私有方法的反射调用
    //类为私有 无法通过类newInstance对象 故通过getDeclaredConstructor获取私有构造方法再通过构造方法newInstance实例对象
    public class reflectTest1 {
        public static void main(String args[]){
            try {
                Class clazz = Class.forName("java.lang.Runtime");
                Constructor con = clazz.getDeclaredConstructor();
                con.setAccessible(true);
                clazz.getMethod("exec",String.class).invoke(con.newInstance(),"calc.exe");
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }

    这个例子的代码如何理解呢?看一下这段反射代码中用到的几个概念

    获取反射中的class对象:

    在反射中,要获取类或调用一个类的方法,我们首先需要获得类的Class对象

    有以下三种方式:

    1. 使用Class.forName方法(也就是例子中的方法)

    2. obj.getClass() 使用类对象的getClass方法

    3. Class clz = test.class 这种方法是已经加载了test这个类,再通过此方法获取一个它的Class对象

    通过反射创建类对象:

    在反射中有两种方式创建类对象

    1. 通过Class对象的newInstance方法

    2. 通过Constructor对象的newInstance方法

    在上个反射的例子中即是使用了Constructor对象的newInstance方法来创建对象,原因是因为使用class.newInstance方法即是调用该类的无参构造函数,而java.lang.runtime类的构造函数是私有的,故不能通过Class对象的newInstance方法创建对象

    否则,编译器会报如下错误

    获取类的方法、构造方法:

    获取类方法:clazz.getMethod、clazz.getDeclaredMethod

    这两者的区别在于getDeclaredMethod可以获取类的私有方法,除此以外它们的结构都是一样的,以getDeclaredMethod官方文档举例可知第一个参数为要获取的方法名,之后为要获取的方法的参数类型。

    因为java中存在方法重载这一概念,所以我们是无法仅通过函数名来确定一个函数的,故在使用getMethod和getDeclaredMethod时我们需要传入要获取的方法的参数类型列表

     获取构造方法:clazz.getConstructor、clazz.getDeclaredConstructor

    其实与获取普通方法类似,因此这里就不细说了。

    执行方法:

    invoke():反射机制使用Method中的invoke方法来调用执行方法,举个简单例子

    Method method = clazz.getMethod("setNumber", int.class); 
    method.invoke(object, 2);

    至此,在前面举例代码中所用到的几个关键方法和概念就清晰了。

    参考:

    https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html

    phithon知识星球

  • 相关阅读:
    SpringBoot项目设置maven打包时间
    SpringBoot热部署配置
    Git笔记
    SpringBoot LogBack日志配置
    CURL使用教程
    Linux 安装Docker及使用
    转发和重定向的区别
    16周作业
    16
    15周
  • 原文地址:https://www.cnblogs.com/escape-w/p/11527161.html
Copyright © 2020-2023  润新知