什么是反射
反射的作用:让java具有动态性
修改已有的属性
动态生成对象
动态调用方法
操作内部类和私有方法
通过java的反射机制,能够判断一个对象所属的类;了解任意一个类的所以属性和方法;能够调用任意一个对象的任意方法和属性
在反序列化漏洞中的应用:
定制需要的对象
通过invoke调用除了同名函数以外的函数
通过Class类创建对象,引入不能序列化的类
反射的基本使用
获取Class类对象
Class.forName 静态方法
Class.forName
如果你知道某个类的名字,想获取到这个类,就可以使⽤ forName 来获取
1
| Class class1 = Class.forName("reflection.TestReflection");
|
使用类的.class 方法
任何数据类型都具备静态的属性,如果你已经加载了某个类,只是想获取到它的 java.lang.Class
对象,那么就直接使用.class
拿它的 class 属性即可
但是要明确用到类的静态成员
这个⽅法其实不属于反射。
1
| Class class2 = TestReflection.class;
|
使用实例对象的 getClass() 方法。
如过上下文中存在某个类的实例obj
,那么可以直接通过obj.getClass()
获取它的字节码对象
1 2
| TestReflection testReflection = new TestReflection(); Class class3 = testReflection.getClass();
|
使用getSystemClassLoader().loadClass()方法
getSystemClassLoader().loadClass()与forName()类似。
但是forName()的静态方法JVM会装载类,并且执行static()中的代码;
而getSystemClassLoader().loadClass()不会执行static()中的代码
反射创造对象
通过反射创建类对象主要有两种方式:
- 通过Class的newInstance()方法 (无参)
- 通过Constructor的newInstance(方法。(可以有参)
eg:
先创建一个person类
1 2 3 4 5 6 7 8 9 10 11 12
| public class person implements Serializable { public String name; public int age; public person(){
} public person(String name,int age){ this.name=name; this.age=age; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import java.lang.reflect.Constructor;
public class reflect { public static void main(String[] args) throws Exception{ Class class1 = Class.forName("person"); person pe = (person) class1.newInstance(); System.out.println(pe); Constructor constructor = class1.getConstructor(); person pe1 = (person) constructor.newInstance(); System.out.println(pe1); } }
|
反射获取类的构造器
- getConstructors() 获取类的所有公共的构造方法
- getDeclaredConstructors() 获取所有的构造方法(公有和私有)
- getConstructor(Class[] parameterTypes) 返回指定参数类型public的构造器
- getDeclaredConstructor (Class[] parameterTypes) 返回指定参数类型的private和public的构造器
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import java.lang.reflect.Constructor;
public class reflect { public static void main(String[] args) throws Exception{ Class class1 = Class.forName("person"); Constructor[] constructor = class1.getDeclaredConstructors(); for (int i=0;i<constructor.length;i++){ System.out.println(constructor[i]); } } }
|
1 2 3 4 5 6 7 8 9 10
| import java.lang.reflect.Constructor;
public class reflect { public static void main(String[] args) throws Exception{ Class class1 = Class.forName("person"); Constructor constructor = class1.getDeclaredConstructor(new Class[]{String.class,int.class}); System.out.println(constructor); } }
|
反射获取类的成员变量
先创建一个person类
1 2 3 4 5 6 7 8 9 10 11 12
| public class person implements Serializable { public String name; public int age; private int home; public person(){
} public person(String name,int age){ this.name=name; this.age=age; } }
|
getFields()
获取当前类或父类或父接口的 public 修饰的字段。
1 2 3
| person person = new person(); Class<?> name = person.getClass(); Field[] getFields = name.getFields();
|
getDelcaredFields()
获取当前类的所有字段,包括 protected/默认/private/public修饰的字段;但是不包括父类public修饰的字段。
1 2 3
| person person = new person(); Class<?> name = person.getClass(); Field[] declaredFields = name.getDeclaredFields();
|
getField()
getField(String name)
根据变量名,返回一个具体的具有public属性的成员变量。包括父类中的public字段
1 2 3
| person person = new person(); Class<?> name = person.getClass(); Field Field = name.getField("name");
|
getDeclaredField()
getDeclaredField(String name)
根据变量名,返回一个成员变量,可以获取本类所有的字段,包括private的,但是不能获取继承来的字段
1 2 3
| person person = new person(); Class<?> name = person.getClass(); Field DeclaredField = name.getDeclaredField("home");
|
修改类的属性值
getField.set()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import java.lang.reflect.Constructor; import java.lang.reflect.Field;
public class reflect { public static void main(String[] args) throws Exception{ person pe = new person(); Class c = pe.getClass(); Constructor constructor = c.getConstructor(String.class,int.class); person p = (person) constructor.newInstance("zzz",123); System.out.println(p); Field field = c.getField("name");
field.set(p,"wzx"); System.out.println(p); } }
|
field.setAccessible(true);
可以让我们给private属性的成员赋值,一般配合getDeclaredField()
使用
获取类属性值
Field.get()方法的功能:
获取对象的Field属性值
Field.get()方法的语法:
get(Object obj)
返回值说明
返回传入对象的值
注意事项:
如果不是静态字段,传入null的obj值,会抛出相应的错误信息
当是静态字段时,传入任何obj值都可以
反射获取类的方法
getMethods()
获取当前类或父类或父接口的所有public 方法;包含接口中 default 修饰的方法 (JDK1.8)。
1 2
| Class<?> name=ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime"); Method[] Methods = name.getMethods();
|
getDeclaredMethods()
1 2
| Class<?> name=ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime"); Method[] declaredMethods = name.getDeclaredMethods();
|
获取当前类或接口声明的所有方法;包括 protected/默认/private/public修饰的方法;不包括父类 、接口 public 修饰的方法。
getMethod()
getMethod(String name,Class[] parameterTypes)
只能返回一个特定的方法,一个参数为目标方法名称,第二个参数为目标方法的参数对应Class的对象
获取范围:自身能用所有的公共方法。
1.类本身的public
2.继承父类的public
3.实现接口的public
1 2
| Class<?> name=Class.forName("java.lang.Runtime"); Method Method = name.getMethod("exec", String.class);
|
getDeclaredMethod()
getDeclaredMethod(String name,Class[] parameterTypes)
跟getMethod()一样,只能返回一个特定的方法,一个参数为目标方法名称,第二个参数为目标方法的参数对应Class的对象
但是获取的范围不同,可以获得自身类的private或public特定方法
1 2
| Class<?> name=Class.forName("java.lang.Runtime"); Method declaredMethod = name.getDeclaredMethod("runFinalization0", null);
|
eg:
给person加一个私有方法和公有方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.io.*;
public class person implements Serializable { public String name; public int age; private int home; public person(){
} public person(String name,int age){ this.name=name; this.age=age; }
private void readObject(ObjectInputStream ois) throws IOException,ClassNotFoundException{ ois.defaultReadObject(); Runtime.getRuntime().exec("calc");
} public void test(String a) { System.out.println(a); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import java.io.ObjectInputStream; import java.lang.reflect.Method;
public class reflect { public static void main(String[] args) throws Exception{ Class class1 = Class.forName("person"); Method method = class1.getDeclaredMethod("readObject", ObjectInputStream.class); System.out.println(method); Method method1 = class1.getMethod("test", String.class); System.out.println(method1); } }
|
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
| import java.io.ObjectInputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method;
public class reflect { public static void main(String[] args) throws Exception{ Class class1 = Class.forName("person"); Method [] method = class1.getDeclaredMethods(); for (int i=0;i<method.length;i++){ System.out.println(method[i]); } System.out.println("分割线================"); Method[] method1 = class1.getMethods(); for (int i=0;i<method1.length;i++){ System.out.println(method1[i]); } } }
|
调用获取的类
public Object invoke( Object obj,Object... args )
1 2 3 4 5 6 7 8 9 10 11
| public class reflect { public static void main(String[] args) throws Exception{ person pe = new person(); Class c = pe.getClass(); Constructor constructor = c.getConstructor(String.class,int.class); person p = (person) constructor.newInstance("zzz",123);
Method method = c.getMethod("test", String.class); method.invoke(p,"persontest"); } }
|