视频 反射 1.java中什么是反射(方法,字段)
在类运行时动态获取类的信息,调用对象方法已经操作的字典
使用反射可以在不知道类结构的情况下,动态调用类的方法和访问类的属性
2.反射核心类
下面几个都是java.long包下面的
Class:类的元数据,可以获取类的信息,如:方法 字段 构造函数
Method:类的方法
Field:类的字段
Construcror:类的构造函数
3.反射作用
在框架中动态的加载和实例化类
在序列化和反序列化中操作类的属性
在测试框架中动态调用测试方法
4.反射原理
主要通过java反射的核心机制Class类来实现
Class.forName()方法获取Class对象
类名.class获取对象
大概的反射代码demo如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package day2; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class Demo { public static void main(String[] args) throws Exception { Class<?> stringClass = String.class;//使用Class 获取类对象 Constructor<?> constructor = stringClass.getConstructor(String.class);//使用Constructor获取构造函数 String str = (String) constructor.newInstance("反射机制案例");// 构造函数实例化对象 Method lengthMethod = stringClass.getMethod("length");// String类的length()方法 int length = (int) lengthMethod.invoke(str);//获取字符串长度 System.out.println("长度为:" + length); // 删掉下面这两行反射访问私有字段的代码 // Field valueField = String.class.getDeclaredField("value"); // valueField.setAccessible(true); // 直接用 String 自带的方法获取字符数组 char[] value = str.toCharArray(); System.out.println("值为:" + new String(value)); } }
反射优点和缺点
优点:
缺点:
大概的demo1如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 package day2; import java.lang.reflect.Field; public class Demo1 { public static void main(String[] args) throws Exception { Student studentOne = new Student(1, "测试", 12); // 实例化对象 studentOne 并赋值 Student studentTwo = new Student(); // 实例化对象 studentTwo 没有赋值 Class clazz = studentTwo.getClass(); // 获取 Student 类对象 Field[] declaredFields = clazz.getDeclaredFields(); // 获取 Student 类所有属性 for (Field field : declaredFields) { field.setAccessible(true); // 设置私有属性可见 field.set(studentTwo, field.get(studentOne)); // 使用 set 方法把 studentOne 对象的值赋给 studentTwo 对象 } System.out.println(studentTwo); } } class Student { private int id; private String name; private int age; public Student() { } public Student(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
demo3大概如下,是java反射和序列化相关的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 import java.io.*; import java.lang.reflect.Method; public class Demo2 implements Serializable { private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); try { Method method = java.lang.Runtime.class.getMethod("exec", String.class); Object result = method.invoke(Runtime.getRuntime(), "calc.exe"); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { Demo2 demo2 = new Demo2(); fileTest.writer(demo2); fileTest.read(); } } class Person implements Serializable { private int id; private String name; private String password; public Person() {} public Person(int id, String name, String password) { this.id = id; this.name = name; this.password = password; } // Getter and Setter methods (if needed) public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + '}'; } } class fileTest { public static void writer(Object one) { try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("demo.one")); oos.writeObject(one); oos.flush(); oos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static void read() { try { File file = new File("demo.one"); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); Object x = ois.readObject(); System.out.print(x); ois.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }
大概是这样吧!但是只是看他的这样视频,是没有懂最基础的java开发知识从而得到安全相关的东西
代理 1.java中什么是代理
一种设置模式,主要对其对象提供一个代理用来便于对该对象的控制访问
2.代理分类
静态代理:编译时确定代理类和被代理类的关系
动态代理:运行时生成代理类
目标类:原始对象
代理类:代理模式产生的对象
Person对象 Student对象
下面是静态代理的
IIEST.java
1 2 3 4 5 6 7 package daili; // 公共接口 public interface ITest { void out(); }
StaticProxy.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package daili; // 真实主题类(被代理类) class RealSubject implements daili.ITest { @Override public void out() { System.out.println("out接口实现"); } } // 代理类 class Proxy implements daili.ITest { private RealSubject realSubject; public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void out() { // 调用被代理对象之前的额外操作 System.out.println("调用被代理对象之前的操作"); realSubject.out(); // 调用被代理对象之后的额外操作 System.out.println("调用被代理对象之后的操作"); } } // 测试主类 public class StaticProxy { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); Proxy proxy = new Proxy(realSubject); proxy.out(); } }
动态代理
一个是什么label的,一个是JDK的
。。。
代理作用
反射文章 参考大佬文章https://blog.csdn.net/ngztx/article/details/142600266?ops_request_misc=elastic_search_misc&request_id=29eaffce9fb5679c8fb9a10fa5897a78&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-142600266-null-null.142^v102^control&utm_term=java%E5%8F%8D%E5%B0%84%E5%AE%89%E5%85%A8&spm=1018.2226.3001.4187
前言 在java rce黑名单绕过还有反序列化的时候都会用到这个反射相关的知识
反射的概念 在Java 程序中,JVM 加载完一个类后,在堆 内存 中就会产生该类的一个 Class 对象,一个类在堆内存中最多只会有一个 Class 对象,这个Class 对象包含了该类的完整结构信息,我们通过这个 Class 对象便可以得到该类的完整结构信息。(注:大写的Class是名为Class的实例对象,先理解Class的存在)
由于JVM为每个加载的类class创建了对应的Class类对象,并在实例中保存了该类class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等。因此,如果获取了某个Class类对象,我们就可以通过这个Class类对象获取到其对应的类class的所有信息,这个过程形象的成为反射。 反射机制是 Java实现动态语言的关键,也就是通过反射实现类的动态加载
Class对象,注意:这个Class类对象是 JVM 内部创建的,如果我们查看 JDK 源码,可以发现Class类的构造方法是private,即只有 JVM 能创建Class类对象,我们程序员自己的 Java 程序是无法创建Class类对象的
1 public final class Class { private Class() {} }
反射组成相关的类 java反射机制组成需要重点注意以下的类:(下面都会讲到具体的使用)
java.lang.Class:类对象;
java.lang.reflect.Constructor:类的构造器对象;
java.lang.reflect.Field:类的属性对象;
java.lang.reflect.Method:类的方法对象;
反射常见的使用方法 获取类的方法:forname
实例化类对象的方法:newInstance
获取函数的方法:getMethod
执行函数的方法:invok
后续会在代码演示中依次介绍 invok()函数在后续漏洞利用中会嵌套使用(个人理解)注意后方高能
为什么要学他 其实从官方定义中就能找到其存在的价值,在运行时获得程序或程序集中每一个类型的成员和成员的信息,从而动态的创建、修改、调用、获取其属性,而不需要事先知道运行的对象是谁。划重点:在运行时而不是编译时。(不改变原有代码逻辑,自行运行的时候动态创建和编译即可
其次,安全应用场景: 构造利用链,触发命令执行 反序列化中的利用链构造 动态获取或执行任意类中的属性或方法 动态代理的底层原理是反射技术 rmi反序列化也涉及到反射操作
代码演示 Java-反射-Class对象类获取 你获取的是.class文件,就是.java稍微编译了一下的那个文件
1 2 3 4 5 //1、根据类名:类名.class Class userClass = User.class; //2、根据对象:对象.getClass() User user = new User(); Class aClass = user.getClass(); //3、根据全限定类名:Class.forName("全路径类名") Class aClass1 = Class.forName("com.example.reflectdemo.User"); //4、通过类加载器获得Class对象://ClassLoader.getSystemClassLoader().loadClass("全路径类名"); ClassLoader clsload=ClassLoader.getSystemClassLoader(); Class aClass2 = clsload.loadClass("com.example.reflectdemo.User");
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.example.reflectdemo; public class GetClass { public static void main(String[] args) throws ClassNotFoundException { //1,根据全限定类名:Class.forName("全路径类名“);适用于在运行时动态加载类。当类名是以字符串形式存在时(例如从配置文件或用户输入获取),可以用这种方式来获取类的元信息。 Class aClass =Class.forName("com.example.reflectdemo.User"); System.out.println(aClass); //2.根据类名:类名.class;适用于在编译时已知类名的情况。相比 Class.forName,这种方式更简单和安全,编译时即可检查类是否存在。 Class userClass = User.class; System.out.println(userClass); //3.根据对象:对象.getClass();适用于在运行时已有某个类的实例对象的情况。通过对象的 getClass 方法可以获取到该对象对应的类的 Class 对象。 User user =new User(); Class aClass1 = user.getClass(); System.out.println(aClass1); //4、通过类加载器获得Class对象://ClassLoader.getSystemClassLoader().loadClass("全路径类名"); //获取系统类加载器;使用类加载器加载指定路径的类,并返回 Class 对象 ClassLoader clsload=ClassLoader.getSystemClassLoader(); Class aClass2 = clsload.loadClass("com.example.reflectdemo.User"); System.out.println(aClass2); } }
但是佬的文章有一些方面没有讲清楚 在不是很懂的情况下,我们要完整的刨析一下原理
先直接把代码复制到IDEA里面,运行肯定是会失败的 因为他的结构应该是在软件包com.example.reflectdemo下面,有两个java类 一个是User类,一个是GetClass类 User类的内容大概可以是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 // 包名必须和文件夹路径一致:com/example/reflectdemo package com.example.reflectdemo; /** * 被反射的User类 * 可以是空类,也可以加属性/方法,不影响获取Class对象 */ public class User { // 可选:加一些属性/方法,让类更贴近实际场景(不加也能运行) private String name; private int age; // 无参构造(默认会有,写出来更清晰) public User() {} // 有参构造 public User(String name, int age) { this.name = name; this.age = age; } // 可选:get/set方法(不加不影响核心功能) public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
这个时候就会有一些问题了,但是一个com.example.reflectdemo软件包下有User类和GetClass类,我GetClass类的内容中,不是已经写了Class aClass = Class.forName(“com.example.reflectdemo.User”); System.out.println(“方式1结果:” + aClass);,你都知道有com.example.reflectdemo.User这个了,为什么还要再画蛇添足呢?
1 2 Class aClass = Class.forName("com.example.reflectdemo.User"); System.out.println("方式1结果:" + aClass);
Class.forName(“com.example.reflectdemo.User”)在代码里面申明了要找的地址目标 Class.forName(“com.example.reflectdemo.User”)返回的是User类的Class对象 这个对象里存着 User 类的所有元信息:比如类名、包名、有哪些属性、有哪些方法、构造方法是什么样的; 它不是 User 类的实例(不是new User()创建的那个对象),而是「描述 User 类本身」的特殊对象; 每个类在 JVM 中只有唯一一个这样的 Class 对象(不管用 4 种方式中的哪一种获取,返回的都是同一个
对于Class aClass = Class.forName(“com.example.reflectdemo.User”); System.out.println(“方式1结果:” + aClass);应该是没有什么问题了
然后还有一点补充的就是 IDEA在原来的语句下面画了黄色的波浪线,Class aClass = Class.forName(“com.example.reflectdemo.User”); System.out.println(“方式1结果:” + aClass);,然后我按照他的提示点了一下,IDEA自动帮我把它改为了 Class<?> aClass = Class.forName(“com.example.reflectdemo.User”);
Class aClass:相当于你声明了一个 “装任意类元信息的盒子”,但没告诉编译器 “这个盒子能装啥”—— 编译器不确定你要装 User、String 还是其他类的 Class 对象,所以标黄提醒你 “可能不安全”; Class> aClass:> 是 “无界通配符”,意思是 “这个盒子可以装任意类的 Class 对象,但我明确告诉编译器‘我知道是任意类型’”—— 这是 Java 5 引入泛型后,处理未知类型 Class 对象的标准、安全写法,所以 IDEA 会自动帮你改成这种形式,消除警告
因为在JVM里面,数组什么的都是以Class的形式存在的,即JVM 里都是以 Class 对象的形式存在的
所以
1 2 3 4 5 6 7 8 9 10 Class aClass1 = Class.forName("com.example.reflectdemo.User"); System.out.println("1. 原始类型:" + aClass1); // 2. 无界通配符(IDE自动推荐,无警告) Class<?> aClass2 = Class.forName("com.example.reflectdemo.User"); System.out.println("2. 无界通配符:" + aClass2); // 3. 明确指定User类型(最严谨) Class<User> aClass3 = User.class; System.out.println("3. 指定User类型:" + aClass3);
这三个表示都是可以的
第一个应该是看懂了,没有什么问题了
第二个解释
1 2 Class userClass = User.class; System.out.println("方式2结果:" + userClass);
User.class;中的User:你定义的 com.example.reflectdemo.User 类的类名 class:Java 特殊语法,直接从 JVM 缓存中获取 User 类的 Class 对象(拿图纸),不是方法、不是属性
第三份解释
1 User user = new User (); Class aClass1 = user.getClass (); System.out.println (aClass1);
1 2 3 4 5 6 7 第一行拆解:User user = new User (); User:变量类型声明,代表这个变量只能存 User 类的实例对象(具体的 “汽车”); user:自定义变量名,存放 User 实例的 “盒子”; =:赋值符号; new User():创建 User 类的实例对象(造一辆具体的 User 牌 “汽车”),调用 User 的无参构造方法。
1 2 3 4 5 6 7 8 第二行拆解:Class aClass1 = user.getClass (); Class:变量类型声明,只能存类的 Class 对象(图纸); aClass1:自定义变量名,存放 Class 对象的 “盒子”; =:赋值符号; user:引用上面创建的 User 实例(具体的 “汽车”); .getClass():所有 Java 对象都有的方法,作用是 “让实例告诉我们它对应的类的图纸(Class 对象)”。就是因为.getClass是让实例化告诉我们,所以我们第一行是先进行实例化
第三行不需要拆解了
方式4: ClassLoader clsload=ClassLoader.getSystemClassLoader (); Class aClass2 = clsload.loadClass (“com.example.reflectdemo.User”); System.out.println (aClass2);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 第一行拆解:ClassLoader clsload=ClassLoader.getSystemClassLoader (); ClassLoader:变量类型声明,代表这个变量只能存 “类加载器” 对象(JVM 的 “快递员”); clsload:自定义变量名,存放类加载器的 “盒子”; =:赋值符号; ClassLoader.getSystemClassLoader():获取 JVM 默认的 “系统类加载器”(核心快递员,负责加载 classpath 下的类)。 第一行大白话翻译: 「准备一个装 “快递员” 的盒子(类型 ClassLoader),命名为 clsload,然后把 JVM 的 “系统快递员” 放进这个盒子里。」 第二行拆解:Class aClass2 = clsload.loadClass ("com.example.reflectdemo.User"); Class:变量类型声明,只能存类的 Class 对象(图纸); aClass2:自定义变量名,存放 Class 对象的 “盒子”; =:赋值符号; clsload:引用上面的系统类加载器(快递员); .loadClass():类加载器的核心方法,接收 “类的全限定名” 字符串,作用是 “让快递员根据地址找类文件,加载到内存并返回 Class 对象”; "com.example.reflectdemo.User":传给 loadClass 的参数,即 User 类的完整地址(包名 + 类名)。 第二行大白话翻译: 「准备一个装 “类图纸” 的盒子(类型 Class),命名为 aClass2,然后让 clsload 这个 “快递员” 去 “com/example/reflectdemo” 地址找 User 类的文件,找到后加载到内存,把生成的 User 类图纸放进盒子里。」 第三行拆解:System.out.println (aClass2); System.out.println():标准输出语句; aClass2:引用上面的变量,即 “装着 User 类图纸的盒子”。
前面不是说了,这三种表示的方式了嘛
1 2 3 4 5 6 7 8 9 10 Class aClass1 = Class.forName("com.example.reflectdemo.User"); System.out.println("1. 原始类型:" + aClass1); // 2. 无界通配符(IDE自动推荐,无警告) Class<?> aClass2 = Class.forName("com.example.reflectdemo.User"); System.out.println("2. 无界通配符:" + aClass2); // 3. 明确指定User类型(最严谨) Class<User> aClass3 = User.class; System.out.println("3. 指定User类型:" + aClass3);
所以整个代码也可以换一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package com.example.reflectdemo; /** * 演示获取Class对象的4种方式 * 注意:必须和User类在同一个包下 */ public class GetClass { public static void main(String[] args) throws ClassNotFoundException { // 方式1:Class.forName("全限定类名") —— 动态加载,运行时找类 Class<?> aClass = Class.forName("com.example.reflectdemo.User"); System.out.println("方式1结果:" + aClass); // 方式2:类名.class —— 编译时已知类名,最安全 Class<User> userClass = User.class; System.out.println("方式2结果:" + userClass); // 方式3:对象.getClass() —— 已有对象,通过对象找类 User user = new User(); // 创建User实例 Class<? extends User> aClass1 = user.getClass(); System.out.println("方式3结果:" + aClass1); // 方式4:类加载器.loadClass("全限定类名") —— 用类加载器加载类 ClassLoader clsload = ClassLoader.getSystemClassLoader(); // 获取系统类加载器 Class<?> aClass2 = clsload.loadClass("com.example.reflectdemo.User"); System.out.println("方式4结果:" + aClass2); } }
这里就只看一下第三种不太一样的 重点拆解泛型 <? extends User>
1 2 3 4 5 ?:通配符,代表 “任意类型”; extends User:限定这个 “任意类型” 必须是 User 类或者 User 的子类(比如如果有class Student extends User {},Student 也符合条件)。 👉 核心含义:aClass1 这个变量只能存放「User 类」或「User 子类」的 Class 对象,不能存 String、Integer 等无关类的 Class 对象 —— 这是比 Class<?> 更精准的类型限定
所以,对于第三种的, <?>这些也是可以的,或者不要也是可以的
小结:Class对象类的获取,这四种方式还有不同的代码表示应该都是没有任何问题的了
Java-反射-Field成员变量类获取 获取成员变量Field位于java.lang.reflect.Field包中
Field[] getFields() :获取所有public修饰的成员变量
Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
Field getField(String name) 获取指定名称的 public修饰的成员变量
Field getDeclaredField(String name) 获取指定的成员变量
第一个获取类的没有什么问题了 上面这个的代码也没有什么太大的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 package com.example.reflectdemo; import java.lang.reflect.Field; public class GetFiled { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { Class aClass =Class.forName("com.example.reflectdemo.User"); //1.获取public属性的成员变量 // Field[] fields = aClass.getFields(); //接收所有成员变量时用数组接收 // for(Field fd:fields){ // System.out.println(fd); // } //2.获取所有的成员变量 Field[] fieldss = aClass.getDeclaredFields(); //3.获取单个的pubilc属性成员变量 Field fd1 = aClass.getField("name"); //4.获取单个的任意属性成员变量 Field fd = aClass.getDeclaredField("job"); System.out.println(fd); //获取公共成员变量age的值 User u = new User(); Field field=aClass.getField("age"); //取值 Object a=field.get(u); System.out.println(a); //赋值 field.set(u,30); Object aa=field.get(u); System.out.println(aa); } }
Java-反射-Method成员方法类获取 Method getMethod(String name, 类<?>… parameterTypes) //返回该类所声明的public方法
Method getDeclaredMethod(String name, 类<?>… parameterTypes) //返回该类所声明的所有方法
//第一个参数获取该方法的名字,第二个参数获取标识该方法的参数类型
Method[] getMethods() //获取所有的public方法,包括类自身声明的public方法,父类中的public方法、实现的接口方法
Method[] getDeclaredMethods() // 获取该类中的所有方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package com.example.reflectdemo; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class GetMethod { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class aClass =Class.forName("com.example.reflectdemo.User"); //1.获取包括继承的公共成员方法 Method[] methods = aClass.getMethods(); for (Method m:methods){ System.out.println(m); } //2.获取不包括继承的所有成员方法 Method[] method = aClass.getDeclaredMethods(); for(Method me:method){ System.out.println(me); } //3.获取单个的成员方法,通过方法名和参数区分是哪个方法 Method users = aClass.getDeclaredMethod("users", String.class); System.out.println(users); //对成员方法进行执行 User u = new User(); Method user = aClass.getDeclaredMethod("users", String.class); user.invoke(u,"gay1");//调用 } }
运行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public void com.example.reflectdemo.User.useinfo(java.lang.String,int,java.lang.String) public final void java.lang.Object.wait() throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public java.lang.String java.lang.Object.toString() public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() protected void com.example.reflectdemo.User.users(java.lang.String) public void com.example.reflectdemo.User.useinfo(java.lang.String,int,java.lang.String) protected void com.example.reflectdemo.User.users(java.lang.String) users成员方法:gay1
Java-反射-Constructor构造方法类获取 Constructor<?>[] getConstructors() :只返回public构造函数
Constructor<?>[] getDeclaredConstructors() :返回所有构造函数
Constructor<> getConstructor(类<?>… parameterTypes) : 匹配和参数配型相符的public构造函数
Constructor<> getDeclaredConstructor(类<?>… parameterTypes) : 匹配和参数配型相符的构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package com.example.reflectdemo; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class GetConstructor { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Class aClass =Class.forName("com.example.reflectdemo.User"); //1.获取公共的构造方法 Constructor[] constructors = aClass.getConstructors(); for(Constructor con:constructors){ System.out.println(con); } //2.获取所有的构造方法 Constructor[] constructorss = aClass.getDeclaredConstructors(); for(Constructor con:constructorss){ System.out.println(con); } //3.获取单个pubilc构造方法 or 获取带相同参数的成员方法 Constructor constructor = aClass.getConstructor(String.class); System.out.println(constructor); //4.获取单个构造方法 Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class,int.class); System.out.println(declaredConstructor); //5.对构造方法进行操作(两个参数String,int) Constructor con2=aClass.getDeclaredConstructor(String.class,int.class); //临时开启对私有的访问 con2.setAccessible(true); User uu=(User) con2.newInstance("congratulation",30); System.out.println(uu); //6.对构造方法进行操作(1个参数String) Constructor con3=aClass.getDeclaredConstructor(String.class); con3.newInstance("123"); } }
运行结果
1 2 3 4 5 6 7 8 9 10 11 12 public com.example.reflectdemo.User(java.lang.String) public com.example.reflectdemo.User() private com.example.reflectdemo.User(java.lang.String,int) public com.example.reflectdemo.User(java.lang.String) public com.example.reflectdemo.User() public com.example.reflectdemo.User(java.lang.String) private com.example.reflectdemo.User(java.lang.String,int) congratulation 30 com.example.reflectdemo.User@4554617c 我的名字123
Java-反射-不安全命令执行&反序列化链构造 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.example.reflectdemo; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class GetRunExec { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //原生调用 JDK自带的rt.jar //Runtime.getRuntime().exec("calc"); //如果是第三方的jar包呢 Class aClass = Class.forName("java.lang.Runtime"); //获取所有公共包括继承的成员方法 // Method[] methods = aClass.getMethods(); // for(Method me:methods){ // System.out.println(me); // } //获取exec成员方法 Method exec = aClass.getMethod("exec", String.class); //获取getRuntime成员方法 Method getRuntimeMethod = aClass.getMethod("getRuntime"); //调用 getRuntime 方法 返回给 Runtime 的实例 Object runtime = getRuntimeMethod.invoke(aClass);//相当于Runtime.getRuntime() //调用 exec 方法执行命令 "calc.exe" exec.invoke(runtime, "calc.exe"); //相当于Runtime.getRuntime().exec("calc"); } }
刚刚说的invoke()函数的高能使用在这里,之后会在各种绕过中使用这种方法,这次一定要理解懂 通过java反射机制的学习,能够为我们为我们后面的java漏洞分析调试,java漏洞 poc 测试和服务端模板引擎注入等有着十分重要的意义
到这里还是非常基础的知识,如果还是有一些开发方面不太懂的,可以看黑马程序员的java下部191~199的课程 之前我是快速过了一遍,所以得回来补
黑马程序员反射 建议前面开发部分没有看懂的,就跟着阿伟老师手敲一下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 # 1. 反射 ## 1.1 反射的概述: **专业的解释(了解一下):** 是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意属性和方法; 这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。 **通俗的理解:(掌握)** * 利用**反射**创建的对象**可以无视修饰符**调用类里面的内容 * 可以跟**配置文件结合起来使用**,把要创建的对象信息和方法写在配置文件中。 读取到什么类,就创建什么类的对象 读取到什么方法,就调用什么方法 此时当需求变更的时候不需要修改代码,只要修改配置文件即可。 ## 1.2 学习反射到底学什么? 反射都是从class字节码文件中获取的内容。 * 如何获取class字节码文件的对象 * 利用反射如何获取构造方法(创建对象) * 利用反射如何获取成员变量(赋值,获取值) * 利用反射如何获取成员方法(运行) ## 1.3 获取字节码文件对象的三种方式 * Class这个类里面的静态方法forName(“全类名”)**(最常用)** * 通过class属性获取 * 通过对象获取字节码文件对象 代码示例: java //1.Class这个类里面的静态方法forName //Class.forName("类的全类名"): 全类名 = 包名 + 类名 Class clazz1 = Class.forName("com.itheima.reflectdemo.Student"); //源代码阶段获取 --- 先把Student加载到内存中,再获取字节码文件的对象 //clazz 就表示Student这个类的字节码文件对象。 //就是当Student.class这个文件加载到内存之后,产生的字节码文件对象 //2.通过class属性获取 //类名.class Class clazz2 = Student.class; //因为class文件在硬盘中是唯一的,所以,当这个文件加载到内存之后产生的对象也是唯一的 System.out.println(clazz1 == clazz2);//true //3.通过Student对象获取字节码文件对象 Student s = new Student(); Class clazz3 = s.getClass(); System.out.println(clazz1 == clazz2);//true System.out.println(clazz2 == clazz3);//true ## 1.4 字节码文件和字节码文件对象 java文件:就是我们自己编写的java代码。 字节码文件:就是通过java文件编译之后的class文件(是在硬盘上真实存在的,用眼睛能看到的) 字节码文件对象:当class文件加载到内存之后,虚拟机自动创建出来的对象。 这个对象里面至少包含了:构造方法,成员变量,成员方法。 而我们的反射获取的是什么?字节码文件对象,这个对象在内存中是唯一的。 ## 1.5 获取构造方法 规则: get表示获取 Declared表示私有 最后的s表示所有,复数形式 如果当前获取到的是私有的,必须要临时修改访问权限,否则无法使用 | 方法名 | 说明 | | ------------------------------------------------------------ | --------------------------------- | | Constructor<?>[] getConstructors() | 获得所有的构造(只能public修饰) | | Constructor<?>[] getDeclaredConstructors() | 获得所有的构造(包含private修饰) | | Constructor<T> getConstructor(Class<?>... parameterTypes) | 获取指定构造(只能public修饰) | | Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 获取指定构造(包含private修饰) | 代码示例: java public class ReflectDemo2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { //1.获得整体(class字节码文件对象) Class clazz = Class.forName("com.itheima.reflectdemo.Student"); //2.获取构造方法对象 //获取所有构造方法(public) Constructor[] constructors1 = clazz.getConstructors(); for (Constructor constructor : constructors1) { System.out.println(constructor); } System.out.println("======================="); //获取所有构造(带私有的) Constructor[] constructors2 = clazz.getDeclaredConstructors(); for (Constructor constructor : constructors2) { System.out.println(constructor); } System.out.println("======================="); //获取指定的空参构造 Constructor con1 = clazz.getConstructor(); System.out.println(con1); Constructor con2 = clazz.getConstructor(String.class,int.class); System.out.println(con2); System.out.println("======================="); //获取指定的构造(所有构造都可以获取到,包括public包括private) Constructor con3 = clazz.getDeclaredConstructor(); System.out.println(con3); //了解 System.out.println(con3 == con1); //每一次获取构造方法对象的时候,都会新new一个。 Constructor con4 = clazz.getDeclaredConstructor(String.class); System.out.println(con4); } } ## 1.6 获取构造方法并创建对象 涉及到的方法:newInstance 代码示例: java //首先要有一个javabean类 public class Student { private String name; private int age; public Student() { } public Student(String name) { this.name = name; } private Student(String name, int age) { this.name = name; this.age = age; } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * @return age */ public int getAge() { return age; } /** * 设置 * @param age */ public void setAge(int age) { this.age = age; } public String toString() { return "Student{name = " + name + ", age = " + age + "}"; } } //测试类中的代码: //需求1: //获取空参,并创建对象 //1.获取整体的字节码文件对象 Class clazz = Class.forName("com.itheima.a02reflectdemo1.Student"); //2.获取空参的构造方法 Constructor con = clazz.getConstructor(); //3.利用空参构造方法创建对象 Student stu = (Student) con.newInstance(); System.out.println(stu); System.out.println("============================================="); //测试类中的代码: //需求2: //获取带参构造,并创建对象 //1.获取整体的字节码文件对象 Class clazz = Class.forName("com.itheima.a02reflectdemo1.Student"); //2.获取有参构造方法 Constructor con = clazz.getDeclaredConstructor(String.class, int.class); //3.临时修改构造方法的访问权限(暴力反射) con.setAccessible(true); //4.直接创建对象 Student stu = (Student) con.newInstance("zhangsan", 23); System.out.println(stu); ## 1.7 获取成员变量 规则: get表示获取 Declared表示私有 最后的s表示所有,复数形式 如果当前获取到的是私有的,必须要临时修改访问权限,否则无法使用 方法名: | 方法名 | 说明 | | ----------------------------------- | -------------------------------------------- | | Field[] getFields() | 返回所有成员变量对象的数组(只能拿public的) | | Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 | | Field getField(String name) | 返回单个成员变量对象(只能拿public的) | | Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 | 代码示例: java public class ReflectDemo4 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { //获取成员变量对象 //1.获取class对象 Class clazz = Class.forName("com.itheima.reflectdemo.Student"); //2.获取成员变量的对象(Field对象)只能获取public修饰的 Field[] fields1 = clazz.getFields(); for (Field field : fields1) { System.out.println(field); } System.out.println("==============================="); //获取成员变量的对象(public + private) Field[] fields2 = clazz.getDeclaredFields(); for (Field field : fields2) { System.out.println(field); } System.out.println("==============================="); //获得单个成员变量对象 //如果获取的属性是不存在的,那么会报异常 //Field field3 = clazz.getField("aaa"); //System.out.println(field3);//NoSuchFieldException Field field4 = clazz.getField("gender"); System.out.println(field4); System.out.println("==============================="); //获取单个成员变量(私有) Field field5 = clazz.getDeclaredField("name"); System.out.println(field5); } } public class Student { private String name; private int age; public String gender; public String address; public Student() { } public Student(String name, int age, String address) { this.name = name; this.age = age; this.address = address; } public Student(String name, int age, String gender, String address) { this.name = name; this.age = age; this.gender = gender; this.address = address; } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * @return age */ public int getAge() { return age; } /** * 设置 * @param age */ public void setAge(int age) { this.age = age; } /** * 获取 * @return gender */ public String getGender() { return gender; } /** * 设置 * @param gender */ public void setGender(String gender) { this.gender = gender; } /** * 获取 * @return address */ public String getAddress() { return address; } /** * 设置 * @param address */ public void setAddress(String address) { this.address = address; } public String toString() { return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", address = " + address + "}"; } } ## 1.8 获取成员变量并获取值和修改值 | 方法 | 说明 | | ----------------------------------- | ------ | | void set(Object obj, Object value) | 赋值 | | Object get(Object obj) | 获取值 | 代码示例: java public class ReflectDemo5 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { Student s = new Student("zhangsan",23,"广州"); Student ss = new Student("lisi",24,"北京"); //需求: //利用反射获取成员变量并获取值和修改值 //1.获取class对象 Class clazz = Class.forName("com.itheima.reflectdemo.Student"); //2.获取name成员变量 //field就表示name这个属性的对象 Field field = clazz.getDeclaredField("name"); //临时修饰他的访问权限 field.setAccessible(true); //3.设置(修改)name的值 //参数一:表示要修改哪个对象的name? //参数二:表示要修改为多少? field.set(s,"wangwu"); //3.获取name的值 //表示我要获取这个对象的name的值 String result = (String)field.get(s); //4.打印结果 System.out.println(result); System.out.println(s); System.out.println(ss); } } public class Student { private String name; private int age; public String gender; public String address; public Student() { } public Student(String name, int age, String address) { this.name = name; this.age = age; this.address = address; } public Student(String name, int age, String gender, String address) { this.name = name; this.age = age; this.gender = gender; this.address = address; } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * @return age */ public int getAge() { return age; } /** * 设置 * @param age */ public void setAge(int age) { this.age = age; } /** * 获取 * @return gender */ public String getGender() { return gender; } /** * 设置 * @param gender */ public void setGender(String gender) { this.gender = gender; } /** * 获取 * @return address */ public String getAddress() { return address; } /** * 设置 * @param address */ public void setAddress(String address) { this.address = address; } public String toString() { return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", address = " + address + "}"; } } ## 1.9 获取成员方法 规则: get表示获取 Declared表示私有 最后的s表示所有,复数形式 如果当前获取到的是私有的,必须要临时修改访问权限,否则无法使用 | 方法名 | 说明 | | ------------------------------------------------------------ | -------------------------------------------- | | Method[] getMethods() | 返回所有成员方法对象的数组(只能拿public的) | | Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 | | Method getMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象(只能拿public的) | | Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象,存在就能拿到 | 代码示例: java public class ReflectDemo6 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { //1.获取class对象 Class<?> clazz = Class.forName("com.itheima.reflectdemo.Student"); //2.获取方法 //getMethods可以获取父类中public修饰的方法 Method[] methods1 = clazz.getMethods(); for (Method method : methods1) { System.out.println(method); } System.out.println("==========================="); //获取所有的方法(包含私有) //但是只能获取自己类中的方法 Method[] methods2 = clazz.getDeclaredMethods(); for (Method method : methods2) { System.out.println(method); } System.out.println("==========================="); //获取指定的方法(空参) Method method3 = clazz.getMethod("sleep"); System.out.println(method3); Method method4 = clazz.getMethod("eat",String.class); System.out.println(method4); //获取指定的私有方法 Method method5 = clazz.getDeclaredMethod("playGame"); System.out.println(method5); } } ## 1.10 获取成员方法并运行 方法 Object invoke(Object obj, Object... args) :运行方法 参数一:用obj对象调用该方法 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) 代码示例: java package com.itheima.a02reflectdemo1; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflectDemo6 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException { //1.获取字节码文件对象 Class clazz = Class.forName("com.itheima.a02reflectdemo1.Student"); //2.获取一个对象 //需要用这个对象去调用方法 Student s = new Student(); //3.获取一个指定的方法 //参数一:方法名 //参数二:参数列表,如果没有可以不写 Method eatMethod = clazz.getMethod("eat",String.class); //运行 //参数一:表示方法的调用对象 //参数二:方法在运行时需要的实际参数 //注意点:如果方法有返回值,那么需要接收invoke的结果 //如果方法没有返回值,则不需要接收 String result = (String) eatMethod.invoke(s, "重庆小面"); System.out.println(result); } } public class Student { private String name; private int age; public String gender; public String address; public Student() { } public Student(String name) { this.name = name; } private Student(String name, int age) { this.name = name; this.age = age; } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * @return age */ public int getAge() { return age; } /** * 设置 * @param age */ public void setAge(int age) { this.age = age; } public String toString() { return "Student{name = " + name + ", age = " + age + "}"; } private void study(){ System.out.println("学生在学习"); } private void sleep(){ System.out.println("学生在睡觉"); } public String eat(String something){ System.out.println("学生在吃" + something); return "学生已经吃完了,非常happy"; } } ## 面试题: 你觉得反射好不好?好,有两个方向 第一个方向:无视修饰符访问类中的内容。但是这种操作在开发中一般不用,都是框架底层来用的。 第二个方向:反射可以跟配置文件结合起来使用,动态的创建对象,动态的调用方法。 ## 1.11 练习泛型擦除(掌握概念,了解代码) 理解:(掌握) 集合中的泛型只在java文件中存在,当编译成class文件之后,就没有泛型了。 代码示例:(了解) java package com.itheima.reflectdemo; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; public class ReflectDemo8 { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //1.创建集合对象 ArrayList<Integer> list = new ArrayList<>(); list.add(123); // list.add("aaa"); //2.利用反射运行add方法去添加字符串 //因为反射使用的是class字节码文件 //获取class对象 Class clazz = list.getClass(); //获取add方法对象 Method method = clazz.getMethod("add", Object.class); //运行方法 method.invoke(list,"aaa"); //打印集合 System.out.println(list); } } ## 1.12 练习:修改字符串的内容(掌握概念,了解代码) 在这个练习中,我需要你掌握的是字符串不能修改的真正原因。 字符串,在底层是一个byte类型的字节数组,名字叫做value java private final byte[] value; 真正不能被修改的原因:final和private final修饰value表示value记录的地址值不能修改。 private修饰value而且没有对外提供getvalue和setvalue的方法。所以,在外界不能获取或修改value记录的地址值。 如果要强行修改可以用反射: 代码示例:(了解) java String s = "abc"; String ss = "abc"; // private final byte[] value= {97,98,99}; // 没有对外提供getvalue和setvalue的方法,不能修改value记录的地址值 // 如果我们利用反射获取了value的地址值。 // 也是可以修改的,final修饰的value // 真正不可变的value数组的地址值,里面的内容利用反射还是可以修改的,比较危险 //1.获取class对象 Class clazz = s.getClass(); //2.获取value成员变量(private) Field field = clazz.getDeclaredField("value"); //但是这种操作非常危险 //JDK高版本已经屏蔽了这种操作,低版本还是可以的 //临时修改权限 field.setAccessible(true); //3.获取value记录的地址值 byte[] bytes = (byte[]) field.get(s); bytes[0] = 100; System.out.println(s);//dbc System.out.println(ss);//dbc ## 1.13 练习,反射和配置文件结合动态获取的练习(重点) 需求: 利用反射根据文件中的不同类名和方法名,创建不同的对象并调用方法。 分析: ①通过Properties加载配置文件 ②得到类名和方法名 ③通过类名反射得到Class对象 ④通过Class对象创建一个对象 ⑤通过Class对象得到方法 ⑥调用方法 代码示例: java public class ReflectDemo9 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { //1.读取配置文件的信息 Properties prop = new Properties(); FileInputStream fis = new FileInputStream("day14-code\\prop.properties"); prop.load(fis); fis.close(); System.out.println(prop); String classname = prop.get("classname") + ""; String methodname = prop.get("methodname") + ""; //2.获取字节码文件对象 Class clazz = Class.forName(classname); //3.要先创建这个类的对象 Constructor con = clazz.getDeclaredConstructor(); con.setAccessible(true); Object o = con.newInstance(); System.out.println(o); //4.获取方法的对象 Method method = clazz.getDeclaredMethod(methodname); method.setAccessible(true); //5.运行方法 method.invoke(o); } } 配置文件中的信息: classname=com.itheima.a02reflectdemo1.Student methodname=sleep ## 1.14 利用发射保存对象中的信息(重点) java public class MyReflectDemo { public static void main(String[] args) throws IllegalAccessException, IOException { /* 对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去 */ Student s = new Student("小A",23,'女',167.5,"睡觉"); Teacher t = new Teacher("播妞",10000); saveObject(s); } //把对象里面所有的成员变量名和值保存到本地文件中 public static void saveObject(Object obj) throws IllegalAccessException, IOException { //1.获取字节码文件的对象 Class clazz = obj.getClass(); //2. 创建IO流 BufferedWriter bw = new BufferedWriter(new FileWriter("myreflect\\a.txt")); //3. 获取所有的成员变量 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); //获取成员变量的名字 String name = field.getName(); //获取成员变量的值 Object value = field.get(obj); //写出数据 bw.write(name + "=" + value); bw.newLine(); } bw.close(); } } java public class Student { private String name; private int age; private char gender; private double height; private String hobby; public Student() { } public Student(String name, int age, char gender, double height, String hobby) { this.name = name; this.age = age; this.gender = gender; this.height = height; this.hobby = hobby; } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * @return age */ public int getAge() { return age; } /** * 设置 * @param age */ public void setAge(int age) { this.age = age; } /** * 获取 * @return gender */ public char getGender() { return gender; } /** * 设置 * @param gender */ public void setGender(char gender) { this.gender = gender; } /** * 获取 * @return height */ public double getHeight() { return height; } /** * 设置 * @param height */ public void setHeight(double height) { this.height = height; } /** * 获取 * @return hobby */ public String getHobby() { return hobby; } /** * 设置 * @param hobby */ public void setHobby(String hobby) { this.hobby = hobby; } public String toString() { return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", height = " + height + ", hobby = " + hobby + "}"; } } java public class Teacher { private String name; private double salary; public Teacher() { } public Teacher(String name, double salary) { this.name = name; this.salary = salary; } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } /** * 获取 * @return salary */ public double getSalary() { return salary; } /** * 设置 * @param salary */ public void setSalary(double salary) { this.salary = salary; } public String toString() { return "Teacher{name = " + name + ", salary = " + salary + "}"; } } # 2. 动态代理 ## 2.1 好处: 无侵入式的给方法增强功能 ## 2.2 动态代理三要素: 1,真正干活的对象 2,代理对象 3,利用代理调用方法 切记一点:代理可以增强或者拦截的方法都在接口中,接口需要写在newProxyInstance的第二个参数里。 ## 2.3 代码实现: java public class Test { public static void main(String[] args) { /* 需求: 外面的人想要大明星唱一首歌 1. 获取代理的对象 代理对象 = ProxyUtil.createProxy(大明星的对象); 2. 再调用代理的唱歌方法 代理对象.唱歌的方法("只因你太美"); */ //1. 获取代理的对象 BigStar bigStar = new BigStar("鸡哥"); Star proxy = ProxyUtil.createProxy(bigStar); //2. 调用唱歌的方法 String result = proxy.sing("只因你太美"); System.out.println(result); } } java /* * * 类的作用: * 创建一个代理 * * */ public class ProxyUtil { /* * * 方法的作用: * 给一个明星的对象,创建一个代理 * * 形参: * 被代理的明星对象 * * 返回值: * 给明星创建的代理 * * * * 需求: * 外面的人想要大明星唱一首歌 * 1. 获取代理的对象 * 代理对象 = ProxyUtil.createProxy(大明星的对象); * 2. 再调用代理的唱歌方法 * 代理对象.唱歌的方法("只因你太美"); * */ public static Star createProxy(BigStar bigStar){ /* java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法: public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 参数一:用于指定用哪个类加载器,去加载生成的代理类 参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法 参数三:用来指定生成的代理对象要干什么事情*/ Star star = (Star) Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(),//参数一:用于指定用哪个类加载器,去加载生成的代理类 new Class[]{Star.class},//参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法 //参数三:用来指定生成的代理对象要干什么事情 new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /* * 参数一:代理的对象 * 参数二:要运行的方法 sing * 参数三:调用sing方法时,传递的实参 * */ if("sing".equals(method.getName())){ System.out.println("准备话筒,收钱"); }else if("dance".equals(method.getName())){ System.out.println("准备场地,收钱"); } //去找大明星开始唱歌或者跳舞 //代码的表现形式:调用大明星里面唱歌或者跳舞的方法 return method.invoke(bigStar,args); } } ); return star; } } java public interface Star { //我们可以把所有想要被代理的方法定义在接口当中 //唱歌 public abstract String sing(String name); //跳舞 public abstract void dance(); } java public class BigStar implements Star { private String name; public BigStar() { } public BigStar(String name) { this.name = name; } //唱歌 @Override public String sing(String name){ System.out.println(this.name + "正在唱" + name); return "谢谢"; } //跳舞 @Override public void dance(){ System.out.println(this.name + "正在跳舞"); } /** * 获取 * @return name */ public String getName() { return name; } /** * 设置 * @param name */ public void setName(String name) { this.name = name; } public String toString() { return "BigStar{name = " + name + "}"; } } ## 2.4 额外扩展 动态代理,还可以拦截方法 比如: 在这个故事中,经济人作为代理,如果别人让邀请大明星去唱歌,打篮球,经纪人就增强功能。 但是如果别人让大明星去扫厕所,经纪人就要拦截,不会去调用大明星的方法。 java /* * 类的作用: * 创建一个代理 * */ public class ProxyUtil { public static Star createProxy(BigStar bigStar){ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) Star star = (Star) Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), new Class[]{Star.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("cleanWC".equals(method.getName())){ System.out.println("拦截,不调用大明星的方法"); return null; } //如果是其他方法,正常执行 return method.invoke(bigStar,args); } } ); return star; } } ## 2.5 动态代理的练习 对add方法进行增强,对remove方法进行拦截,对其他方法不拦截也不增强 java public class MyProxyDemo1 { public static void main(String[] args) { //动态代码可以增强也可以拦截 //1.创建真正干活的人 ArrayList<String> list = new ArrayList<>(); //2.创建代理对象 //参数一:类加载器。当前类名.class.getClassLoader() // 找到是谁,把当前的类,加载到内存中了,我再麻烦他帮我干一件事情,把后面的代理类,也加载到内存 //参数二:是一个数组,在数组里面写接口的字节码文件对象。 // 如果写了List,那么表示代理,可以代理List接口里面所有的方法,对这些方法可以增强或者拦截 // 但是,一定要写ArrayList真实实现的接口 // 假设在第二个参数中,写了MyInter接口,那么是错误的。 // 因为ArrayList并没有实现这个接口,那么就无法对这个接口里面的方法,进行增强或拦截 //参数三:用来创建代理对象的匿名内部类 List proxyList = (List) Proxy.newProxyInstance( //参数一:类加载器 MyProxyDemo1.class.getClassLoader(), //参数二:是一个数组,表示代理对象能代理的方法范围 new Class[]{List.class}, //参数三:本质就是代理对象 new InvocationHandler() { @Override //invoke方法参数的意义 //参数一:表示代理对象,一般不用(了解) //参数二:就是方法名,我们可以对方法名进行判断,是增强还是拦截 //参数三:就是下面第三步调用方法时,传递的参数。 //举例1: //list.add("阿玮好帅"); //此时参数二就是add这个方法名 //此时参数三 args[0] 就是 阿玮好帅 //举例2: //list.set(1, "aaa"); //此时参数二就是set这个方法名 //此时参数三 args[0] 就是 1 args[1]"aaa" public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //对add方法做一个增强,统计耗时时间 if (method.getName().equals("add")) { long start = System.currentTimeMillis(); //调用集合的方法,真正的添加数据 method.invoke(list, args); long end = System.currentTimeMillis(); System.out.println("耗时时间:" + (end - start)); //需要进行返回,返回值要跟真正增强或者拦截的方法保持一致 return true; }else if(method.getName().equals("remove") && args[0] instanceof Integer){ System.out.println("拦截了按照索引删除的方法"); return null; }else if(method.getName().equals("remove")){ System.out.println("拦截了按照对象删除的方法"); return false; }else{ //如果当前调用的是其他方法,我们既不增强,也不拦截 method.invoke(list,args); return null; } } } ); //3.调用方法 //如果调用者是list,就好比绕过了第二步的代码,直接添加元素 //如果调用者是代理对象,此时代理才能帮我们增强或者拦截 //每次调用方法的时候,都不会直接操作集合 //而是先调用代理里面的invoke,在invoke方法中进行判断,可以增强或者拦截 proxyList.add("aaa"); proxyList.add("bbb"); proxyList.add("ccc"); proxyList.add("ddd"); proxyList.remove(0); proxyList.remove("aaa"); //打印集合 System.out.println(list); } }
ctf赛题 1 NSS,BUU,ctfshow,vilfocus这个CTF靶场关于java的反射和代理有没有什么题目,先不要来和反序列化相关的
我叫ai帮我爬了一下,然后做下那些题目
但是就如文章开篇说的,这个是非常基础的一个知识点,所以可能单独一个方面的题目就比较少,同时相关的代码审计的文章(如公众号菜狗安全什么的,相关的基础就是序列化反序列化的)