Java 反射机制
Java反射机制是在运行时动态地获取类的信息以及调用类的方法和操作类的属性的能力。程序中的对象在编译时只确定下来类型,反射机制允许程序在运行时获取类的信息,如类名、方法、字段、构造函数等,这使得程序可以在运行时动态地加载、探索和使用类,不需要提前在编译时就知道运行的对象是谁,从而增强了程序的灵活性和扩展性。
因此通过反射,对象可以动态地获取类,类可以通过反射拿到所有的方法,包括私有方法,并且可以直接进行调用。使得Java静态语言有了类似于PHP的动态特性(eg:一句话木马)
反射机制常用的类文件
-
Java.lang.Class
:Java反射机制的核心,Class
类代表了Java中的类和接口,可通过该类所提供的方法获取有关类的信息,实现动态加载,创建类的实力,调用 Java.lang.reflect.Constructor;
:表示类的构造函数。可以获取构造函数的信息并实例化对象Java.lang.reflect.Field;
: 表示类的字段(成员变量),可以获取字段的信息并操作类的属性Java.lang.reflect.Method;
: 表示类的方法,可以获取方法的信息并嗲用类的方法。Java.lang.reflect.Modifier;
:是反射机制中的一个工具类,用于解析类,字段,方法等的修饰符。
获取Class对象
通常共三种方式:
类名.class
:e.g.:Parar.class;
(静态方法),如果上下文存在每个实例的对象,且只想获得java.lang.Class
对象时,可以直接通过此方法获得它的类obj.getClass
:如果上下文存在每个实例的对象,可以直接通过此方法获得它的类Class.forName()
:e.g.:Class.forName("Parar");
(不属于反射)知道某个类的名字就可以直接通过此方法获取(后台直接进行加载)
示例:
首先创造一个类:Parar.java
public class Parar {
private int age;
private String name;
public Parar(){
this.age=19;
this.name="Parar";
}
public void selfIntroduction(){
System.out.println("My name is"+name+" and "+age+" years pld.");
}
}
- 通过
类名.class
获取:
Main.java
javapublic class Main {
public static void main(String[] args){
System.out.println(Parar.class);
}
}
- 通过
类名.getClass
方法获取
public class Main {
public static void main(String[] args){
Parar parar = new Parar();
Class<?> clazz = parar.getClass(); //泛型,表示一个未知类型的类,进行通配
System.out.println(clazz);
}
}
-
通过
Class.forName()
public class Main { public static void main(String[] args)throws Exception{ Class<?> clazz =Class.forName("Parar"); System.out.println(clazz); } }
通过反射实例化对象
获得了了Class对象之后,下一步就是将获得的对象进行实例化
-
通过
Class的newInstance
方法public class Main { public static void main(String[] args)throws Exception{ Class<?> clazz =Class.forName("Parar"); Object obj = clazz.newInstance(); System.out.println(obj.toString()); } }
-
通过
Constructor的newInstance()
方法import java.lang.reflect.*; public class Main { public static void main(String[] args)throws Exception{ Class<?> clazz =Class.forName("Parar"); Constructor<?> con = clazz.getConstructor(); Object obj = con.newInstance(); System.out.println(obj); } }
操作属性
根据前两步,已经获得了类并成功将类进行了实例化
通过Class对象的getFields()
(返回数组)或者getField()
方法可以获得该类所包括的全部Field属性或指定Field属性。
FIled
类提供了几种方法进行操作属性
Field.getName()
获取属性名Field.getModifiers()
获取属性的修饰列表Field.getType()
返回属性类型Field.set("obj","value")
对属性进行赋值操作,但无法访问私有属性Field.get("obg")
获取属性值Field.setAccessible(true or false);
打破封装,可以进行set操作
代码示例:
import java.lang.reflect.*;
public class Main {
public static void main(String[] args)throws Exception{
Class<?> clazz =Class.forName("Parar");
Constructor<?> con = clazz.getConstructor();
Object obj = con.newInstance();
//获取属性名
Field field = clazz.getField("name");
String name = field.getName();
System.out.println("getName():"+name);
//获取属性的修饰符列表
int Modifiers = field.getModifiers();
System.out.println("Modifiers():"+Modifiers);
//获取属性类型
Class<?> type=field.getType();
System.out.println("getType():"+type);
//获取属性值
Object oldValue = field.get(obj);
System.out.println("old:field.get()::"+oldValue);
//对对象进行赋值
field.set(obj,"parar");
Object newValue=field.get(obj);
System.out.println("new:field.get()::"+newValue);
}
}
执行方法
- 通过
Class
对象的getMethods()
方法可以获得该类所包括的全部方法, 返回值是Method[] - 通过
Class
对象的getMethod()
方法可以获得该类所包括的指定方法, 返回值是Method - 每个
Method
对象对应一个方法,获得Method对象后,可以调用其invoke("")
来调用对应方法 Object invoke(Object obj,Object [] args):
obj代表当前方法所属的对象的名字,args
代表当前方法的参数列表,返回值Object是当前方法的返回值,即执行当前方法的结果。(当调用静态方法static
时,obj为null)
e.g.:
import java.lang.reflect.*;
public class Main {
public static void main(String[] args)throws Exception{
Class<?> clazz =Class.forName("Parar");
Constructor<?> con = clazz.getConstructor();
Object obj = con.newInstance();
Method method= clazz.getDeclaredMethod("selfIntroduction");
System.out.println("getDeclaredMethod:"+method);
String name = method.getName();
System.out.println("method.getName():"+name);
int Modifiers1=method.getModifiers();
System.out.println("getModifiers: "+Modifier.toString(Modifiers1));
Class<?> returnType = method.getReturnType();
Class<?>[] parameterTypes=method.getParameterTypes();
method.invoke(obj);
}
}