首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Java学习之反射篇

Java学习之反射篇

作者头像
全栈程序员站长
发布于 2022-07-13 10:43:33
发布于 2022-07-13 10:43:33
3290
举报

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Java学习之反射篇

0x00 前言

今天简单来记录一下,反射与注解的一些东西,反射这个机制对于后面的java反序列化漏洞研究和代码审计也是比较重要。

0x01 反射机制概述

Java反射是Java非常重要的动态特性,通过使用反射我们不仅可以获取到任何类的成员方法、成员变量、构造方法等信息,还可以动态创建Java类实例、调用任意的类方法、修改任意的类成员变量值等。Java反射机制是Java语言的动态性的重要体现,也是Java的各种框架底层实现的灵魂。

0x02 Java反射

Java反射操作的是java.lang.Class对象,所以我们需要要先获取到Class对象。

获取Class对象的方式:

代码语言:javascript
AI代码解释
复制
1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
		 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
	2. 类名.class:通过类名的属性class获取
		 多用于参数的传递
	3. 对象.getClass():getClass()方法在Object类中定义着。
		 多用于对象的获取字节码的方式

代码实例:

代码语言:javascript
AI代码解释
复制
方式一:
Class cls1 = Class.forName("Domain.Person");

        System.out.println(cls1);
方式二:
        Class cls2 = Person.class;
        System.out.println(cls2);
        
方式三:

        Person p = new Person();
        Class cls3 = p.getClass();
        System.out.println(cls3);

同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

class类方法:

获取成员变量方法:

代码语言:javascript
AI代码解释
复制
1. 获取成员变量们
			* Field[] getFields() :获取所有public修饰的成员变量
			* Field getField(String name)   获取指定名称的 public修饰的成员变量

			* Field[] getDeclaredFields()  获取所有的成员变量,不考虑修饰符
			* Field getDeclaredField(String name) 

获取构造方法:

代码语言:javascript
AI代码解释
复制
* Constructor<?>[] getConstructors()  
			* Constructor<T> getConstructor(<?>... parameterTypes)  

			* Constructor<T> getDeclaredConstructor(<?>... parameterTypes)  
			* Constructor<?>[] getDeclaredConstructors()  

获取成员方法:

代码语言:javascript
AI代码解释
复制
* Method[] getMethods()  
			* Method getMethod(String name,<?>... parameterTypes)  

			* Method[] getDeclaredMethods()  
			* Method getDeclaredMethod(String name,<?>... parameterTypes)  

获取全类名:

代码语言:javascript
AI代码解释
复制
String getName()  

成员变量设置:

代码语言:javascript
AI代码解释
复制
 Field:成员变量
	* 操作:
		1. 设置值
			* void set(Object obj, Object value)  
		2. 获取值
			* get(Object obj) 

		3. 忽略访问权限修饰符的安全检查
			* setAccessible(true):暴力反射

构造方法:

代码语言:javascript
AI代码解释
复制
创建对象:
		* T newInstance(Object... initargs)  

		* 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法

方法对象:

代码语言:javascript
AI代码解释
复制
执行方法:
		* Object invoke(Object obj, Object... args)  

	* 获取方法名称:
		* String getName:获取方法名
使用getField方法获取成员变量

我们现在这里编写一个person类。

person代码:

代码语言:javascript
AI代码解释
复制
package Domain;

public class Person {
    private String name  ;
    private int age;
    public String a ;


    public Person() {
    }

    public void eat(){
        System.out.println("eat");
    }
    public void eat(String food){
        System.out.println("eat "+food);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                '}';
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

main类代码:

代码语言:javascript
AI代码解释
复制
 public static void main(String[] args) throws Exception {
        Class cls = Class.forName("Domain.Person");
        Field a = cls.getField("a"); //获取成员a变量
        Person person = new Person();
        Object o = a.get(person);  //获取成员变量的值
        System.out.println(o);
        a.set(person,"abc");  //修改成员a变量的值为abc
        System.out.println(person);

    }
使用getDeclaredFields获取所有成员变量

该方法不考虑修饰符

代码语言:javascript
AI代码解释
复制
public static void main(String[] args) throws Exception {
        Class cls = Class.forName("Domain.Person");
    System.out.println(person);
        Field[] declaredFields = cls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
            
        }
使用getDeclaredField获取指定成员变量
代码语言:javascript
AI代码解释
复制
Class cls = Class.forName("Domain.Person");
Field b = cls.getDeclaredField("b");
        b.setAccessible(true);  //使用暴力反射机制,忽略访问权限修饰符的安全检测
        Person person = new Person();
        Object o1 = b.get(person);
        System.out.println(o1);

这里person该类中的成员变量是被private修饰的,我们想要访问他的值必须使用暴力反射,暴力反射 可以,忽略访问权限修饰符的安全检测。

获取构造方法
代码语言:javascript
AI代码解释
复制
Class cls = Class.forName("Domain.Person");

        Constructor constructor = cls.getConstructor(String.class,int.class);//获取构造器
        System.out.println(constructor);
        //有参构造
        Object o = constructor.newInstance("123", 18); //创建对象
        System.out.println(o);
        //无参构造
        Object o1 = constructor.newInstance();
        
        System.out.println(o1);
获取方法
代码语言:javascript
AI代码解释
复制
Class cls = Class.forName("Domain.Person");
        //无参数方法
        Method eat = cls.getMethod("eat");
        Person person = new Person();
        eat.invoke(person);   //调用eat方法
        //有参数方法
        Method eat1 = cls.getMethod("eat", String.class);  //获取eat方法并且设置参数
        eat1.invoke(person,"fish");
获取所有public修饰方法
代码语言:javascript
AI代码解释
复制
Class cls = Class.forName("Domain.Person");
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
获取类名
代码语言:javascript
AI代码解释
复制
Class cls = Class.forName("Domain.Person");
        String name = cls.getName();
        System.out.println(name);

前面这些只是简单的一些方法的使用,后面来看一个小案例来了解反射的具体应用。

步骤

1.首先我们需要创建一个配置文件,然后定义需要创建的兑现和需要执行的方法定义在配置文件里面。

2.在程序中读取配置文件

3.使用反射机制加载类文件进内存

4.创建对象

5.执行方法

一般java里面的配置文件都是以.properites结尾,那么就定义一个pro.properites文件。

pro.properites文件内容:

代码语言:javascript
AI代码解释
复制
className=Domain.Person  //写入需要加载的类
methodName=eat //写入需要加载的方法

main类里面内容:

代码语言:javascript
AI代码解释
复制
public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Properties properties = new Properties(); //创建properties对象
        ClassLoader classLoader = Person.class.getClassLoader();  //获取加载
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properites"); //获取路径文件流
        properties.load(resourceAsStream); //加载文件
        //获取配置文件定义的数据
        String className = properties.getProperty("className"); //获取类名
        String methodName = properties.getProperty("methodName");//获取方法名

        Class cls = Class.forName(className);  //将类加载进内存
        Object o = cls.newInstance(); //创建无参构造对象

        Method method = cls.getMethod(methodName);   //创建方法
        method.invoke(o);      //调用方法




    }
}

如果我们需要修改调用的方法或者说类,可以直接在配置文件里面进行修改,无需修改代码。

0x03 反射调用Runtime

Runtime这个函数有exec方法可以本地执行命令,大部分关于jsp命令执行的payload可能都是调用Runtime进行Runtime的exec方法进行命令执行的。

不利用反射执行命令
代码语言:javascript
AI代码解释
复制
package com;

import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;

public class Test {
    public static void main(String[] args) throws IOException {
        InputStream ipconfig = Runtime.getRuntime().exec("ipconfig").getInputStream();
        String s = IOUtils.toString(ipconfig,"gbk"); //使用IOUtils.toString静态方法将字节输入流转换为字符
        System.out.println(s);


    }
}

这样的代码基本都是固定死的,如果要多次传入参数执行命令的话,这样的写法肯定是不行的,那么这时候就可以用到反射。

代码语言:javascript
AI代码解释
复制
package com;

import org.apache.commons.io.IOUtils;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Test2 {
    public static void main(String[] args) throws Exception {
        String command = "ipconfig";
        Class cls = Class.forName("java.lang.Runtime"); //Runtime加载进内存
        Constructor declaredConstructor = cls.getDeclaredConstructor(); //获取构造方法
        declaredConstructor.setAccessible(true);  //暴力反射
        Object o = declaredConstructor.newInstance(); //创建Runtime类
        Method exec = cls.getMethod("exec", String.class); //获取exec方法,设置需要参数string类型参数
        Process process = (Process) exec.invoke(o,command);   //执行exec方法,并传入ipconfig参数
//        System.out.println(process);
        InputStream inputStream = process.getInputStream();    //获取输出的数据
        String ipconfig = IOUtils.toString(inputStream,"gbk"); //字节输出流转换为字符
        System.out.println(ipconfig);
    }
}

这时候只需要修改command的值,无需修改代码就可以执行其他的命令了。

method.invoke的第一个参数必须是类实例对象,如果调用的是static方法那么第一个参数值可以传null,因为在java中调用静态方法是不需要有类实例的,因为可以直接类名.方法名(参数)的方式调用。

method.invoke的第二个参数不是必须的,如果当前调用的方法没有参数,那么第二个参数可以不传,如果有参数那么就必须严格的依次传入对应的参数类型。

0x04 结尾

一边调试代码,一边码文章,写完不知不觉已经5点了。还是洗洗睡吧。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/119946.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年12月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java反射:框架设计的灵魂
框架:半成品软件。可以在框架的基础上进行软件开发,简化编码。 反射就是把Java类中的各个成员映射成一个个的Java对象。         即在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;         对于任意一个对象,都能调用它的任意一个方法和属性。 这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。 好处:
共饮一杯无
2022/11/28
3590
Java反射知识
(2)Class类对象阶段:*.class字节码文件被类加载器加载进内存,并将其封装成Class对象(用于在内存中描述字节码文件),Class对象将原字节码文件中的成员变量抽取出来封装成数组Field[],将原字节码文件中的构造函数抽取出来封装成数组Construction[],在将成员方法封装成Method[]。当然Class类内不止这三个,还封装了很多,一般常用的就这三个。
乐心湖
2020/07/31
4850
Java反射知识
2-反射
Class.forName(“全类名”):将字节码文件加载进内存,返回Class类对象
Ywrby
2022/10/27
2760
2-反射
Java Web_基础加强
反射 反射:框架设计的灵魂 * 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码 * 反射:将类的各个组成部分封装为其他对象,这就是反射机制 * 好处: 1. 可以在程序运行过程中,操作这些对象。 2. 可以解耦,提高程序的可扩展性。
全栈程序员站长
2021/05/20
6750
Java-反射
哈喽!大家好,我是小简。今天开始学习《Java-反射》,此系列是我做的一个 “Java 从 0 到 1 ” 实验,给自己一年左右时间,按照我自己总结的 Java-学习路线,从 0 开始学 Java 知识,并不定期更新所学笔记,期待一年后的蜕变吧!
小简
2023/01/04
5120
Java-反射
Java反射:Web学习的灵魂
我们将类分为三部分,成员变量,构造方法,成员方法,代码编译后,变成了字节码文件(.class文件)而万物皆对象,所以在字节码文件中,又将这三部分分别整合成对象,所以我们得出结论:
BWH_Steven
2019/08/09
3850
Java知识点——反射初识以及基本API
.class字节码文件 .java文件 通过 javac编译工具生成对应的.class字节码文件 使用JDK中提供的反编译工具,可以看到.class文件中包含 Class 完整的包名.类名 Field 成员变量,成员变量的名字和成员变量的数据类型[如果是引用数据类型,也是 完整的包名.类名] Method 成员方法,方法权限修饰符,返回值类型,方法名,形式参数列表数据类型
用户7073689
2020/03/17
5700
Java基础——反射
Java除了基本类型其他都是class,包括interface,String,Object Runnable,Exception class的本质是数据类型Type 无继承关系的数据类型无法赋值 class/insterface的数据类型是class 每加载一个class,JVM就为其创建一个Class类型的实例,并关联起来 JVM持有的每个Class实例都指向一个数据类型 一个Clas实例包含
羊羽shine
2019/05/28
3860
利用反射技术提升Java应用的灵活性和可扩展性
结论:**同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个**。
杨不易呀
2023/09/26
2760
利用反射技术提升Java应用的灵活性和可扩展性
java学习与应用(3.6.1)--测试、反射、注解
Junit单元测试:黑盒测试(不关注内部逻辑,只关注输入输出),白盒测试(关注执行流程,需要些代码)。 测试类使用对应定义的测试类(测试用例,类名为XxxTest,包名为xxx.xxx.test等),方法名为testXxx,返回值void,参数列表为空,@Test注解使得独立运行(测试)。需要导入Junit依赖。 然后通过编译器调用测试类中的测试方法即可。测试通过为绿色(编译成功)。 断言类Assert,包含方法assertEquals方法,定义期望的值为指定值,用于判断运算是否成功。 定义好:init方法,初始化,用于资源申请,添加@Before方法。close方法,结束后执行,用于释放资源,使用@After(抛出异常仍然会执行)。
嘘、小点声
2020/02/18
4900
java学习与应用(3.6.1)--测试、反射、注解
Java反射研究和实践
本博文中项目代码已开源下载地址:GitHub Java反射研究和实践 概述 Java的反射机制是Java语言动态性的一种体现。反射机制是通过反射API来实现的,它允许程序在运行过程中取得任何一个已知名称的类的内部信息,包括其中的构造方法、声明的字段和定义的方法等。这不得不说是一个很强大的能力。 正如英文单词reflection的含义一样,使用反射API的时候就好像在看一个Java类在水中的倒影一样。知道了Java类的内部结构之后,就可以与它进行交互,包括创建新的对象和调用对象中的方法等。这种交互方式与直
CrazyCodeBoy
2018/05/07
7500
反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
2022/05/10
3500
Java反射
反射:框架设计的灵魂 框架:半成品,可以在框架的基础上进行软件开发,简化编码 反射:将类的各个组成部分封装为其他的对象,这就是反射机制 好处: 1.可以在程序的运行过程中,操作这些对象 2.可以解耦,提高程序的可拓展性
一只胡说八道的猴子
2020/09/27
7680
Java反射
Java反射详解
Class.forName("全类名"):将字节码文件加载到内存,返回Class对象;
訾博ZiBo
2025/01/06
2870
Java反射详解
【深入浅出Java原理及实战】「源码分析系列」深入分析反射功能基础使用和原理
Java代码基础结构 Java代码都在类内或者接口内 访问修饰符 【class/interface/enum】 类名 { 成员变量 构造方法 成员方法 Annotation 注解 } Class字节码在内存中分布 图片 Class字节码和Java代码 图片 Class类相关方法 Class: Class.forName(String packageNameAndCl
码界西柚
2023/02/28
3330
【深入浅出Java原理及实战】「源码分析系列」深入分析反射功能基础使用和原理
Java反射详解
这样的需求在学习框架时特别多,即通过外部文件配置,在不修改源码情况下。来控制程序,也符合设计模式的ocp原则(开闭原则:不修改源码,扩容功能)。
timerring
2023/05/24
4530
Java反射详解
谈谈Java中的反射机制
在使用框架进行开发时,我们的开发速度大大提升。我们感叹于它的神奇之处,我们使用它的时候,也要知道其“灵魂”。正所谓,无反射,不框架,框架的灵魂就是反射。 另外,我们在eclipse或者IDEA中编辑Java代码时,它们是怎么知道我们的对象有哪些方法,输入一个点就能给提示呢? 带着问题我们来谈谈反射。
code随笔
2020/05/20
5420
【Java学习】反射和枚举详解
可以看出,使用getDeclaredConstructors()时,不论构造方法的权限修饰符是什么,都可以获取到
2的n次方
2024/10/15
2540
【Java学习】反射和枚举详解
Java 反射机制详解
将类的各个组成部分封装为其他对象的过程就叫做 反射,其中 组成部分 指的是我们类的 成员变量(Field)、构造方法(Constructor)、成员方法(Method)。
村雨遥
2023/05/30
2980
Java 反射机制详解
初探java安全之反射(1)
上次和亮去接了个渗透的比赛,结果我还是啥都不会,当时意识到现在大多数的网站的后端都基本上是 java 和 go了,想 php 的基本上比较少了,php 在以后肯定会没落的,java不想 php 那样 简单易用且灵活,所以很有必要系统性的学习一下java安全。
pankas
2022/10/08
3590
初探java安全之反射(1)
相关推荐
Java反射:框架设计的灵魂
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
首页
学习
活动
专区
圈层
工具
MCP广场
首页
学习
活动
专区
圈层
工具
MCP广场