什么是反射
反射的作用:让java具有动态性
修改已有的属性
动态生成对象
动态调用方法
操作内部类和私有方法
通过java的反射机制,能够判断一个对象所属的类;了解任意一个类的所以属性和方法;能够调用任意一个对象的任意方法和属性
在反序列化漏洞中的应用:
定制需要的对象
通过invoke调用除了同名函数以外的函数
通过Class类创建对象,引入不能序列化的类
反射的基本使用
获取Class类对象
Class.forName 静态方法
Class.forName
如果你知道某个类的名字,想获取到这个类,就可以使⽤ forName 来获取
Class class1 = Class.forName("reflection.TestReflection");
使用类的.class 方法
任何数据类型都具备静态的属性,如果你已经加载了某个类,只是想获取到它的 java.lang.Class
对象,那么就直接使用.class
拿它的 class 属性即可
但是要明确用到类的静态成员
这个⽅法其实不属于反射。
Class class2 = TestReflection.class;
使用实例对象的 getClass() 方法。
如过上下文中存在某个类的实例obj
,那么可以直接通过obj.getClass()
获取它的字节码对象
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类
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;
}
}
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);
}
}
//person@1b6d3586
//person@4554617c
反射获取类的构造器
- getConstructors() 获取类的所有公共的构造方法
- getDeclaredConstructors() 获取所有的构造方法(公有和私有)
- getConstructor(Class[] parameterTypes) 返回指定参数类型public的构造器
- getDeclaredConstructor (Class[] parameterTypes) 返回指定参数类型的private和public的构造器
eg:
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]);
}
}
}
//public person()
//public person(java.lang.String,int)
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);
}
}
//public person(java.lang.String,int)
反射获取类的成员变量
先创建一个person类
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 修饰的字段。
person person = new person();
Class<?> name = person.getClass();
Field[] getFields = name.getFields();
getDelcaredFields()
获取当前类的所有字段,包括 protected/默认/private/public修饰的字段;但是不包括父类public修饰的字段。
person person = new person();
Class<?> name = person.getClass();
Field[] declaredFields = name.getDeclaredFields();
getField()
getField(String name)
根据变量名,返回一个具体的具有public属性的成员变量。包括父类中的public字段
person person = new person();
Class<?> name = person.getClass();
Field Field = name.getField("name");
getDeclaredField()
getDeclaredField(String name)
根据变量名,返回一个成员变量,可以获取本类所有的字段,包括private的,但是不能获取继承来的字段
person person = new person();
Class<?> name = person.getClass();
Field DeclaredField = name.getDeclaredField("home");
修改类的属性值
getField.set()
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);
}
}
//person{name=zzz,age=123}
//person{name=wzx,age=123}
field.setAccessible(true);
可以让我们给private属性的成员赋值,一般配合getDeclaredField()
使用
获取类属性值
Field.get()方法的功能:
获取对象的Field属性值
Field.get()方法的语法:
get(Object obj)
返回值说明
返回传入对象的值
注意事项:
如果不是静态字段,传入null的obj值,会抛出相应的错误信息
当是静态字段时,传入任何obj值都可以
反射获取类的方法
getMethods()
获取当前类或父类或父接口的所有public 方法;包含接口中 default 修饰的方法 (JDK1.8)。
Class<?> name=ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime");
Method[] Methods = name.getMethods();
getDeclaredMethods()
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
Class<?> name=Class.forName("java.lang.Runtime");
Method Method = name.getMethod("exec", String.class);
getDeclaredMethod()
getDeclaredMethod(String name,Class[] parameterTypes)
跟getMethod()一样,只能返回一个特定的方法,一个参数为目标方法名称,第二个参数为目标方法的参数对应Class的对象
但是获取的范围不同,可以获得自身类的private或public特定方法
Class<?> name=Class.forName("java.lang.Runtime");
Method declaredMethod = name.getDeclaredMethod("runFinalization0", null);
eg:
给person加一个私有方法和公有方法
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);
}
}
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);
}
}
//private void person.readObject(java.io.ObjectInputStream) throws java.io.IOException,java.lang.ClassNotFoundException
//public void person.test(java.lang.String)
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]);
}
}
}
//private void person.readObject(java.io.ObjectInputStream) throws java.io.IOException,java.lang.ClassNotFoundException
//public void person.test(java.lang.String)
// 分割线================
//public void person.test(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()
调用获取的类
public Object invoke( Object obj,Object... args )
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");
}
}