访问静态成员
静态成员的获取和普通的成员获取方法一致,但静态成员不需要在对象上执行(在反射中这样表述更合乎语法一些),所以不需要传入承载的对象,也就不需要获得类的对象。
package testReflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
//自定的一个类
class MyClass {
private static double a1;// 静态成员变量
// 主方法也是静态成员方法
public static void main(String[] args) {
System.out.println("静态方法执行了");
System.out.println(Arrays.toString(args));
}
}
// 在主类main方法中测试
public class Main {
public static void main(String[] args) {
try {
// 加载类
Class cls = Class.forName("testReflect.MyClass");
// 从Class对象获取指定的成员方法
Method mthd = cls.getDeclaredMethod("main", String[].class);
// mthd.setAccessible(true);
// 调用该成员方法,静态方法不需有载体对象因此传入null,还需传入参数并上转型到Object类型
mthd.invoke(null, (Object) new String[] { "刘知昊", "大傻逼" });
// 从Class对象获取指定的成员
Field f1 = cls.getDeclaredField("a1");
// 暴力反射,让这个私有静态成员变量可以越过权限检查
f1.setAccessible(true);
// 为成员变量设置值,无载体对象,还需传入值
f1.set(null, 8.88);
// 输出这个静态成员变量的值,于null无对象上(即表示静态成员变量)
System.out.println("静态成员变量a1=" + f1.get(null));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
输出:
静态方法执行了
[刘知昊, 大傻逼]
静态成员变量a1=8.88
越过泛型检查
泛型是在编译期间起作用的,也就是在java类编译成class文件的过程中,会根据书写的泛型的具体类型,来对泛型类的对象的增删改查做类型检查。当编译完成,生成class文件之后,类型检查就不再起作用了,即做了泛型擦除使泛型中的实参不再生效。
反射通过class文件中的Class类的对象,复活这个类甚至对象,这个过程中该类或者该对象是没有经过编译的,而是从编译好的class文件中取出来的,所以用使用反射时也就避开了泛型检查。
package testReflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
// 在主类main方法中测试
public class Main {
private static ArrayList<String> al = new ArrayList<>();
public static void main(String[] args) {
// 获取其Class对象
Class cls = al.getClass();
try {
// 获取其add方法,注意绕过了泛型的add参数完全是Object类型的
Method mthd = cls.getDeclaredMethod("add", Object.class);
// 添加一些其它类型的元素进去试试
mthd.invoke(al, 100);
mthd.invoke(al, true);
mthd.invoke(al, 3.14);
// 查看一下
System.out.println(al.toString());
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
输出:
[100, true, 3.14]