欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > Java安全基础-反射机制

Java安全基础-反射机制

2025/4/8 0:54:05 来源:https://blog.csdn.net/weixin_45534587/article/details/146919134  浏览:    关键词:Java安全基础-反射机制

目录

1. 什么是反射?

2.反射的核心操作 

2.1  反射组成相关的类

2.2  反射常见使用的方法

2.3  如何获取Class对象?

2.4  获取成员变量Field

2.5  获取成员方法Method

2.6  获取构造函数Constructor

2.7  反射创建类对象及调用方法

2.7.1  创建类对象

2.7.2  调用实例方法

 2.7.3  调用静态方法

 2.8  利用反射构造Runtime类执行

2.9  设置setAccessible(true)暴力访问权限 


1. 什么是反射?

反射是一种动态机制,能够在程序运行时:

  • 动态获取类信息(属性、方法、构造器)
  • 突破封装性限制(访问私有成员)
  • 动态创建对象与调用方法

想象你在餐厅点餐,服务员递给你一本菜单。传统方式是根据菜单上的菜品直接点单,但反射就像你拿到菜单后,不仅能看到菜品名称,还能知道每道菜的原料、烹饪方法,甚至可以要求厨师按照你的方式调整口味。Java 反射机制赋予程序在运行时动态解析类结构的能力,让代码具备了类似 "透视" 的魔法。

2.反射的核心操作 

2.1  反射组成相关的类

反射机制相关操作一般位于java.lang.reflect包中。

而java反射机制组成需要重点注意以下的类:

java.lang.Class:类对象;

java.lang.reflect.Constructor:类的构造器对象;

java.lang.reflect.Field:类的属性对象;

java.lang.reflect.Method:类的方法对象;

2.2  反射常见使用的方法

获取类的方法:forname

实例化类对象的方法:newInstance

获取函数的方法:getMethod

执行函数的方法:invoke

2.3  如何获取Class对象?

在反射中,我们想获取一个类或调用一个类的方法,需要先获取到该类的Class对象。而Class类构造器是私有的,所以只有JVM能够创建Class对象(了解),所以是无法通过创建对象的方式来获取class对象的,一般我们获取class对象就有以下三种方法:

// 三种获取Class对象的方式
Class<?> clazz1 = String.class;          // 通过类名的属性class获取。
Class<?> clazz2 = "test".getClass();     // 实例化一个对象,之后在调用getClass()方法。
Class<?> clazz3 = Class.forName("java.util.Date"); // 调用Class类中的forName方法,将字节码文件加载进内存,返回Class对象。动态加载

而这三种获取Class类方式中,一般使用第三种通过Class.forName方法去动态加载类。且使用forName就不需要import导入其他类,可以加载我们任意的类。 

getClass()方法,需要本身创建一个对象,就没有了使用反射机制意义。

类.class属性,需要导入类的包,依赖性太强,在大型项目中容易抛出编译错误;

 

2.4  获取成员变量Field

获取成员变量Field位于java.lang.reflect.Field包中

Field[] getFields() :获取所有public修饰的成员变量

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

Field getField(String name) 获取指定名称的 public修饰的成员变量

Field getDeclaredField(String name) 获取指定的成员变量

 

package com.reflect;import java.lang.reflect.Field;public class FieldTest {public String name;public String profession;protected int age;private String number;char sex;public static void main(String[] args){try{Class c1 = Class.forName("com.reflect.FieldTest"); // 创建Class对象Field[] fieldArray1 = c1.getDeclaredFields(); //获取全部成员变量Field[] fieldArray2 = c1.getFields();// 获取全部public成员变量System.out.println("全部成员变量");for (Field field : fieldArray1){System.out.println(field.getName());}System.out.println("-------分割线---------");System.out.println("全部public成员变量");for (Field field : fieldArray2){System.out.println(field.getName());}System.out.println("-------分割线---------");System.out.println("获取指定名称的public修饰的成员变量");Field fieldArray3 = c1.getField("name"); // 获取指定名称的public修饰的成员变量System.out.println(fieldArray3.getName());System.out.println("-------分割线---------");System.out.println("获取指定的成员变量");Field fieldArray4 = c1.getDeclaredField("number"); // 获取指定的成员变量System.out.println(fieldArray4.getName());} catch (Exception e) {e.printStackTrace();}}
}

 

2.5  获取成员方法Method

Method getMethod(String name, 类<?>... parameterTypes) //返回该类所声明的public方法

Method getDeclaredMethod(String name, 类<?>... parameterTypes) //返回该类所声明的所有方法

//第一个参数获取该方法的名字,第二个参数获取标识该方法的参数类型

Method[] getMethods() //获取所有的public方法,包括类自身声明的public方法,父类中的public方法、实现的接口方法

Method[] getDeclaredMethods() // 获取该类中的所有方法

package com.reflect;import java.lang.reflect.Method;public class MethodTest {public void study(String s) {System.out.println("学习中..." + s);}protected void run() {System.out.println("跑步中...");}void eat() {System.out.println("吃饭中...");}private String sleep(int age) {System.out.println("睡眠中..." + age);return "sleep";}public static void main(String[] args) {try {Class c = Class.forName("com.reflect.MethodTest"); // 创建Class对象Method[] methods1 = c.getDeclaredMethods(); // 获取所有该类中的所有方法Method[] methods2 = c.getMethods(); // 获取所有的public方法,包括类自身声明的public方法,父类中的public方法、实现的接口方法System.out.println("获取所有该类中的所有方法");for (Method m:methods1) {System.out.println(m);}System.out.println("-------分割线---------");System.out.println("获取所有的public方法,包括类自身声明的public方法,父类中的public方法、实现的接口方法");for (Method m:methods2) {System.out.println(m);}System.out.println("-------分割线---------");System.out.println("获取study方法");Method methods3 = c.getMethod("study", String.class); // 获取study方法System.out.println(methods3);System.out.println("-------分割线---------");System.out.println("获取sleep方法");Method method4 = c.getDeclaredMethod("sleep", int.class); // 获取sleep方法System.out.println(method4);} catch (Exception e) {e.printStackTrace();}}
}

2.6  获取构造函数Constructor

Constructor<?>[] getConstructors() :只返回public构造函数

Constructor<?>[] getDeclaredConstructors() :返回所有构造函数

Constructor<> getConstructor(类<?>... parameterTypes) : 匹配和参数配型相符的public构造函数

Constructor<> getDeclaredConstructor(类<?>... parameterTypes) : 匹配和参数配型相符的构造函数

 

package com.reflect;import java.lang.reflect.Constructor;
public class ConstructorTest {public ConstructorTest() {System.out.println("无参构造函数");}public ConstructorTest(String name) {System.out.println("有参构造函数" + name);}private ConstructorTest(boolean n) {System.out.println("私有构造函数");}public static void main(String[] args) {try {Class c1 = Class.forName("com.reflect.ConstructorTest");Constructor[] constructors1  = c1.getDeclaredConstructors();Constructor[] constructors2 = c1.getConstructors();System.out.println("只返回public构造函数");for (Constructor c : constructors1) {System.out.println(c);}System.out.println("-------分割线---------");System.out.println("返回所有构造函数");for (Constructor c : constructors2) {System.out.println(c);}System.out.println("-------分割线---------");System.out.println(" 匹配和参数配型相符的public构造函数");Constructor constructors3 = c1.getConstructor(String.class);System.out.println(constructors3);System.out.println("-------分割线---------");System.out.println(" 匹配和参数配型相符的构造函数");Constructor constructors4 = c1.getDeclaredConstructor(boolean.class);System.out.println(constructors4);} catch (Exception e) {e.printStackTrace();}}
}

 2.7  反射的应用

在Java的反射机制中,java.lang.reflect.Method类的invoke()方法扮演着核心角色。它允许我们在运行时动态调用对象的方法,无论是实例方法还是静态方法。一般会和getMethod方法配合进行调用。

public Object invoke(Object obj, Object... args) 

2.7  反射创建类对象及调用方法

2.7.1  创建类对象

一般我们使用Class对象的newInstance()方法来进行创建类对象。只需要通过forname方法获取到的class对象中进行newInstance方法创建即可。

Class c = Class.forName("com.reflect.MethodTest"); // 创建Class对象
Object m1 =  c.newInstance(); // 创建类对象

2.7.2  调用实例方法

当需要调用一个对象的实例方法时,invoke()的第一个参数应传入该对象的实例。

package com.reflect;import java.lang.reflect.Method;public class InvokeExample {public void printMessage(String message) {System.out.println("实例方法输出: " + message);}public static void main(String[] args) throws Exception {// 使用完整的类名(包含包路径)Class<?> clazz = Class.forName("com.reflect.InvokeExample");// 创建类的实例Object instance = clazz.newInstance();// 获取printMessage方法对象Method method = clazz.getMethod("printMessage", String.class);// 调用实例方法method.invoke(instance, "Hello, World!");}
}

 2.7.3  调用静态方法

对于静态方法,invoke()的第一个参数应传入null,因为静态方法属于类本身,而非类的实例。 

package com.reflect;import java.lang.reflect.Method;public class InvokeExample {public static int add(int a, int b) {return a + b;}public static void main(String[] args) throws Exception {// 获取MathUtils的Class对象Class<?> clazz = Class.forName("com.reflect.InvokeExample");// 获取add方法对象Method method = clazz.getMethod("add", int.class, int.class);// 调用静态方法(第一个参数为null)Object result = method.invoke(null, 5, 3);System.out.println("静态方法结果: " + result);}
}

 

 2.8  利用反射构造Runtime类执行

平时漏洞测试中,如何使用java反射中如何获取Runtime类来命令执行测试弹出计算器。

尝试通过反射机制调用Runtime.getRuntime().exec()方法,执行系统命令打开系统的计算器应用。

package com.reflect;import java.lang.reflect.Method;public class RuntimeTest {public static void main(String[] args) throws Exception {Class c1 = Class.forName("java.lang.Runtime");Object m = c1.newInstance();}
}

 

在Java反射机制中,当尝试通过Class.newInstance()直接实例化一个类时,若该类的构造函数被声明为private,则会抛出IllegalAccessException。原因是因为在Java标准库中,java.lang.Runtime类采用了经典的单例模式设计,其通过私有构造函数+静态工厂方法的组合,完美实现了对单例的管控。

1.私有构造函数Runtime类的构造函数被显式声明为private,禁止外部直接通过new关键字或反射创建实例。

2.静态工厂方法:提供public static Runtime getRuntime()方法作为唯一获取实例的途径,确保全局唯一性。 

所以通过反射获取getRuntime静态方法并调用,绕过了私有构造函数的限制。

package com.reflect;import java.lang.reflect.Method;public class RuntimeDemo {public static void main(String[] args) throws Exception {Class<?> clazz = Class.forName("java.lang.Runtime");// 获取getRuntime方法(静态方法)Method getRuntime = clazz.getMethod("getRuntime");Object runtime = getRuntime.invoke(null);  // 静态方法传null// 调用exec方法Method exec = clazz.getMethod("exec", String.class);exec.invoke(runtime, "calc.exe");  // 弹出计算器(Windows)}
}

2.9  设置setAccessible(true)暴力访问权限 

在Java反射体系中,java.lang.reflect.AccessibleObject类扮演着关键角色。作为FieldMethodConstructor类的共同基类,它提供了setAccessible()方法这一"特权通道",使得反射机制能够突破访问控制限制。

AccessibleObject

├─ Field(字段反射类)

├─ Method(方法反射类)

└─ Constructor(构造器反射类)

所有反射对象都继承自AccessibleObject,因此都拥有setAccessible()方法。

所有我们最开始的代码再修改简略下,就能成功命令执行了。

package com.reflect;import java.lang.reflect.Constructor;public class RuntimeTest {public static void main(String[] args) throws Exception {Class c1= Class.forName("java.lang.Runtime");Constructor m = c1.getDeclaredConstructor();m.setAccessible(true);c1.getMethod("exec", String.class).invoke(m.newInstance(), "calc");}
}

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词