写在前面
第一次学习java反射,可能有些错误,希望师傅们能及时指正我QAQ
什么是反射
- 反射机制的核心是在程序运行时动态加载类并获取类的各种信息,从而操作类或者对象的属性和方法。
本质是:JVM得到class对象后,再通过class对象进行反编译,从而获得对象的各种信息
- Java属于先编译再运行的语言,程序中对象的类型再编译器就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所有没有被加载到JVM中,通过反射,就可以再运行时动态的创建对象并调用其属性和方法,不需要提前在编译期知道运行的对象是谁
反射常用的类
- Java.lang.Class
- Java.lang.reflect.Field
- Java.lang.reflect.Method
- Java.lang.reflect.Constructor
- Java.lang.reflect.Modifier
先抛出我写的类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Member{ public String name; protected int age; private String sex;
public Member() { System.out.println("这是无参构造函数"); } public void aaa(int num){ System.out.println("今年是"+num+"年"); }
private void bbb(int num){ System.out.println("本月是"+num+"月"); } @Override public String toString() { return "Member{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}'; }
|
Class类对象的获取
- 根据类名:类名.class
- 根据对象:对象.getClass()
- 根据路径包:Class.forName(“绝对路径”)
1 2 3 4 5 6 7 8 9 10
| Class memberClass = Member.class;
Member member = new Member(); Class aClass = member.getClass();
Class aClass1 = Class.forName("com.Reflection.Member");
|
通过观察hashcode发现三者相等
获取Class类对象的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
Class aClass = Class.forName("com.Reflection.Member"); Field name = aClass.getField("name"); Field age = aClass.getField("age"); Field sex = aClass.getField("sex");
|
我们发现这里报错了,说代码36行age出现了问题
回首我们发现,age是属于protected的类型,sex是属于private的
getFileld只能获得public的属性,那么怎样才能获得protected和private呢?
getDeclaredField是专门用来获取所有得属性或者方法(包括了protected和private)
换掉之后便不在报错了~
记得要加 对象.setAccessible(true) ,用来解除private和protect
获取Class类对象的方法
1 2
| Method aaa = aClass.getMethod("aaa", int.class); Method bbb = aClass.getDeclaredMethod("bbb", int.class);
|
也是一样的,用getDeclaredMethod获得private和protect
class.newInstance()
会调用这个类得无参构造函数
有时候我们会newInstance不成功,原因如下:
- 你使用得类没有无参构造函数
- 你使用得类构造函数是私有的
1 2
| Object obj = aClass.newInstance(); System.out.println(obj);
|
尝试输出一下
提问:
- 如果一个类没有无参构造方法,也没有静态模块,那么我们应该怎样通过反射实例化这个类呢?
- 如果一个方法或者构造方法是私有方法,我们是否能执行它了?
解答
解答一:
我们这时候就要用到一个新的反射方法getConstructor
它与getMethod的用法相似,获得构造函数后,使用newInstance来执行
1 2 3 4
| Method declaredMethod = aClass.getDeclaredMethod("aaa", int.class); Constructor declaredConstructor = aClass.getDeclaredConstructor(); Object o = declaredConstructor.newInstance(); declaredMethod.invoke(o,2022);
|
解答二:
答案很简单,就是直接用getDeclared
记得要加 对象.setAccessible(true) ,用来解除private和protect
整个源代码给出
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
| package com.Reflection;
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class Test11 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class aClass = Class.forName("com.Reflection.Member");
Field name = aClass.getField("name"); Field age = aClass.getDeclaredField("age"); Field sex = aClass.getDeclaredField("sex");
Method bbb = aClass.getDeclaredMethod("bbb", int.class); Method aaa = aClass.getDeclaredMethod("aaa", int.class);
Constructor declaredConstructor = aClass.getDeclaredConstructor(); Object o = declaredConstructor.newInstance();
name.set(o,"CQJKL"); age.setAccessible(true); age.set(o,10); sex.setAccessible(true); sex.set(o,"boy"); System.out.println(o);
aaa.invoke(o,2022); bbb.setAccessible(true); bbb.invoke(o,5);
}
}
class Member{ public String name; protected int age; private String sex;
public Member() { System.out.println("这是无参构造函数"); }
public void aaa(int num){ System.out.println("今年是"+num+"年"); }
private void bbb(int num){ System.out.println("本月是"+num+"月"); } @Override public String toString() { return "Member{" + "name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + '}'; } }
|
再更新
这两天中秋节,花了两个早上把韩顺平老师的java反射给刷了一遍
这里来贴上韩老师的相关代码,经过自己改编的QAQ
师傅们可以看看我写的有没有问题,哈哈
构造器实例
- 方式一:调用类中二点public修饰的无参构造器
- 方式二:调用类中的指定构造器
- Class类相关方法
- newInstance:调用类中的无参构造器,获取对应类得对象
- getConstructor:根据参数列表,获取对于得构造器对象
- getDecalaredConstructor:根据参数列表,获取对应得构造器对象
- Constructor类相关方法
- setAccessible:爆破
- newInstance:调用构造器
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
| package com.Reflection;
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;
public class demo1 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { Class<?> cls = Class.forName("com.Reflection.Persion");
Object o = cls.newInstance(); System.out.println(o); System.out.println("======================================"); Constructor<?> constructor = cls.getConstructor(String.class); Object cqjkl = constructor.newInstance("cqjkl"); System.out.println(cqjkl); System.out.println("======================================"); Constructor<?> declaredConstructor = cls.getDeclaredConstructor(int.class, String.class); declaredConstructor.setAccessible(true); Object CQjkl = declaredConstructor.newInstance(55, "CQjkl"); System.out.println(CQjkl);
} }
class Persion{ private int age = 10; private String name = "CQJKL";
public Persion() { } public Persion(String name) { this.name = name; }
private Persion(int age, String name){ this.age = age; this.name = name; }
@Override public String toString() { return "Persion{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
|
属性实例
- 根据属性名获取Field对象
- Field f = clazz对象.getDeclaredField(属性名);
- 爆破:f.setAccessible(true);
- 访问
- f.set(o,value)
- System.out.println(f.get(o));
- 如果是静态属性,则set和get中得参数o,可以写成null
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
| package com.Reflection;
import java.lang.reflect.Field;
public class demo2 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException { Class<?> stu = Class.forName("com.Reflection.Stu"); Object o = stu.newInstance(); System.out.println(o); Field age = stu.getField("age"); age.set(o,55); System.out.println(age.get(o)); Field name = stu.getDeclaredField("name"); name.setAccessible(true); name.set(o,"cqjkl"); System.out.println(name.get(o)); System.out.println(o);
} }
class Stu{ public int age = 5; private String name = "CQJKL";
public Stu(){
}
@Override public String toString() { return "Stu{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
|
方法实例
- 根据方法名和参数列表获取Method方法对象:Method m = clazz.getDeclaredMethod(方法名,XX.class);
- 获取对象:Object o = clazz.newInstance();
- 爆破:m.setAccessible(true);
- 访问:Object returnValue = m.invoke;
- 注意:如果是静态方法,则invoke的参数o,可以写成null
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
| package com.Reflection;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class demo3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Class<?> boss = Class.forName("com.Reflection.Boss"); Object o = boss.newInstance(); Method hi = boss.getMethod("hi", String.class); hi.invoke(o, "CQJKL");
Method say = boss.getDeclaredMethod("say", int.class, String.class, char.class); say.setAccessible(true); System.out.println(say.invoke(o,55,"jk",'H')); Object invoke = say.invoke(null, 44, "JK", 'M'); System.out.println(invoke);
} }
class Boss{ public int age; private static String name;
public Boss(){
} private static String say(int n, String s, char c){ return n + " " + s + " " + c; }
public void hi(String s){ System.out.println("hi "+ s); } }
|
参考
https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html
https://blog.csdn.net/a745233700/article/details/82893076
https://www.bilibili.com/video/BV1g84y1F7df?p=1&vd_source=69176eb1fdd50fb68253b31fc93080b0
https://www.bilibili.com/video/BV1p4411P7V3?spm_id_from=333.999.0.0&vd_source=69176eb1fdd50fb68253b31fc93080b0
<P牛-代码审计-Java安全漫谈-反射篇-3篇>