一、Java反射机制
Java 反射机制在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性。
这种 动态的获取信息 以及 动态调用对象的方法 的功能称为 java 的反射机制。
二、通过反射获取类的信息
2.1、主方法
@Test
void testPrintFields() throws ClassNotFoundException {
/**
* 1、获取并输出类的名称
*/
//1.1获取Class
Class<SonClass> sonClassClass = SonClass.class;
System.out.println("类的全路径名称:" + sonClassClass.getName());
//1.2获取Class
Class<?> aClass = Class.forName("com.chenheng.juejin.reflection.SonClass");
System.out.println("aClass->" + aClass);
//1.3获取Class
Class<? extends SonClass> bClass = new SonClass().getClass();
System.out.println("bClass->" + bClass);
/**
* 2.1、获取所有public访问权限的变量
*/
Field[] fields = sonClassClass.getFields();
/**
* 2.2、获取所有本类声明的变量(不管访问权限)
*/
Field[] declaredFields = sonClassClass.getDeclaredFields();
/**
* 3.1、遍历public变量并输出变量信息(包括子类及父类的public属性信息)
*/
for (Field field : fields) {
//获取访问权限并输出
int modifiers = field.getModifiers();
System.out.println("field modifiers->" + Modifier.toString(modifiers));
//输出变量的类型及变量名
System.out.println("field type->" + field.getType().getName() + "->" + field.getName());
}
/**
* 3.2、所有权限的字段信息(输出的是SonClass子类的所有权限的属性信息)
*/
for (Field declaredField : declaredFields) {
declaredField.setAccessible(true);
//获取访问权限并输出
int modifiers = declaredField.getModifiers();
System.out.println("declaredField modifiers->" + Modifier.toString(modifiers));
//输出变量的类型及变量名
System.out.println("declaredField type->" + declaredField.getType().getName() + "->" + declaredField.getName());
}
}
2.2、其他类
2.2.1、FatherClass
public class FatherClass {
public String mFatherName;
public int mFatherAge;
public void printFatherMsg(){}
}
2.2.2、SonClass
public class SonClass extends FatherClass{
private String mSonName;
protected int mSonAge;
public String mSonBirthday;
/**
* 测试
*/
public List<String> strList;
public String getmSonName() {
return mSonName;
}
public void setmSonName(String mSonName) {
this.mSonName = mSonName;
}
public int getmSonAge() {
return mSonAge;
}
public void setmSonAge(int mSonAge) {
this.mSonAge = mSonAge;
}
}
2.2.3、TestClass
public class TestClass {
private String MSG = "Original";
private final String FINAL_VALUE = "FINAL";
private void privateMethod(String head , int tail){
System.out.print("privateMethod->" + head + "->" + tail);
}
public String getMsg(){
return MSG;
}
public String getFinalValue(){
return FINAL_VALUE;
}
}
三、通过反射获取类方法
3.1、类的公共方法
/**
* 类的公共方法
*/
@Test
void testPrintMethods(){
//1.获取并输出类的名称
Class mClass = SonClass.class;
System.out.println("类的名称:" + mClass.getName());
//2.1 获取所有 public 访问权限的方法
//包括自己声明和从父类继承的
Method[] mMethods = mClass.getMethods();
/**
* 2.2 获取所有本类的的方法(不问访问权限)
* 输出的都是 SonClass 类的方法,不问访问权限
*/
Method[] declaredMethods = mClass.getDeclaredMethods();
//3.遍历所有 public 访问权限的方法
for (Method mMethod : mMethods) {
/**
* 方法权限,例如private、protected、public
*/
int modifiers = mMethod.getModifiers();
System.out.println("mMethods->" + Modifier.toString(modifiers));
/**
* 方法返回类型
*/
Class<?> returnType = mMethod.getReturnType();
System.out.println("returnType->" + returnType);
/**
* 方法入参,参数类型及参数名称
*/
Class<?>[] parameterTypes = mMethod.getParameterTypes();
System.out.println("parameterTypes->" + parameterTypes);
for (Class<?> parameterType : parameterTypes) {
System.out.println("getTypeName->" + parameterType.getTypeName() + "getName->" + parameterType.getName());
}
//获取并输出方法抛出的异常
Class[] exceptionTypes = mMethod.getExceptionTypes();
if (exceptionTypes.length == 0){
System.out.println(" )");
}
else {
for (Class c : exceptionTypes) {
System.out.println(" ) throws "
+ c.getName());
}
}
}
}
3.2、访问私有方法
@Test
void testPrivateMethod(){
/**
* 1.获取 Class 类实例
*/
Class<TestClass> testClassClass = TestClass.class;
try {
//类对象,相当于TestClass testClassObject = new TestClass()
TestClass testClassObject = testClassClass.newInstance();
/**
* 2.获取私有方法
*/
Method privateMethod = testClassClass.getDeclaredMethod("privateMethod", String.class, int.class);
/**
* 通过反射调用方法
*/
if (Objects.nonNull(privateMethod)) {
//可以访问private的方法,只是获取访问权,并不是修改方法权限
privateMethod.setAccessible(true);
//第一个参数是类对象,第二个、第三个是参数
privateMethod.invoke(testClassObject, "Java Reflect", 21);
}
} catch (Exception e) {
e.printStackTrace();
}
}
四、通过反射获取类字段
4.1、修改对象私有变量的值
@Test
void modifyPrivateFiled(){
//获取类
Class<TestClass> testClassClass = TestClass.class;
try {
//获取类对象
TestClass testClassObject = testClassClass.newInstance();
/**
* 获取public修饰的方法
*/
//testClassClass.getField("")
/**
* 获取private修饰的方法
*/
Field privateField = testClassClass.getDeclaredField("MSG");
if (Objects.nonNull(privateField)) {
//获取私有变量的访问权
privateField.setAccessible(true);
System.out.println("Before Modify:MSG = " + testClassObject.getMsg());
/**
* 如果这个字段加final的话,这样无法修改字段值
* 否则是可以修改字段值
*/
privateField.set(testClassObject, "Modified");
System.out.println("After Modify:MSG = " + testClassObject.getMsg());
}
} catch (Exception e) {
e.printStackTrace();
}
}
4.2、修改私有变量
class文件是在程序编译期生成的,编译时候程序实际还并未运行,所以不会牵扯到JVM。这里实际应该是由编译器优化的。
/**
* 修改私有变量
* JVM编译后会优化代码
*/
@Test
void modifyFinalFiled() throws Exception {
/**
* 1.获取 Class 类实例
*/
Class<TestClass> testClassClass = TestClass.class;
/**
* 获取类对象
*/
TestClass testClassObject = testClassClass.newInstance();
/**
* 2.获取私有常量
*/
Field declaredField = testClassClass.getDeclaredField("FINAL_VALUE");
/**
* 3.修改常量的值
*/
if (Objects.nonNull(declaredField)) {
//获取私有常量的访问权
declaredField.setAccessible(true);
//通过反射输出 FINAL_VALUE 修改前的值
System.out.println("Before Modify:FINAL_VALUE = "
+ declaredField.get(testClassObject));
//通过反射修改私有常量
declaredField.set(testClassObject, "Modified");
System.out.println("After Modify:FINAL_VALUE = "
+ declaredField.get(testClassObject));
//使用对象调用类的 getter 方法
//获取值并输出
System.out.println("Actually :FINAL_VALUE = "
+ testClassObject.getFinalValue());
}
}