越过泛型检查
Java泛型检查是指在实例化类时规定了泛型的类型,如
List<Student>l=new ArrayList<>();
所以这时如果想往容器中添加元素(使用add方法等添加),在调用add方法时。这个实例就会检查参数是不是指定的类型,如不是就会报错,java代码过不了编译检查
l.add("添加String类型的字符串"); //检查不通过
上面这样直接使用add是不能通过检查的
而这时我们就可以想到一种利用反射的解决方案:
我们都知道,上面这种检查的原理是基于先实例化对象,然后才能调用方法
List<Student>l=new ArrayList<>();
l.add("添加String类型的字符串"); //检查不通过
而如果我们使用反射的话就存在这样的约束,我们可以直接越过实例化这一步,先调用add方法,最后在指定这个方法是附属于某个实例就可以了
具体步骤:
第一步:获得字节码文件
Listl=new ArrayList<>();
Class c=l.getClass();
第二步:指定调用的是名字为add的方法,add的入参类型为object
Method m=c.getDeclaredMethod(“add”,Object.class);
第三步:指定所属对象,完成实参传入:
m.invoke(l,“字符串”);
m.invoke(l,“不是Student却加入了容器”);
实现如下
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class test_5 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<Student>l=new ArrayList<>();
Class c=l.getClass();
Method m=c.getDeclaredMethod("add",Object.class);
m.invoke(l,"字符串");
m.invoke(l,"不是Student却加入了容器");
System.out.println(l);
}
}
控制台输出
越过泛型检查成功
暴力反射
暴力反射就是原本受到private修饰的值在其他类中不能进行取值修改等操作,但是可以使用反射进行操作
如Student类中有一个private修饰的age变量为0
Student类:
private int age=0;
正常情况下在另外一个测试类中是无法直接使用age的
Student s=new Student();
Systen.out.println(s.age); //这里会因为没有访问权限而报错
解决方案:
第一步:获得字节码文件
Class c= Student.class;
第二步:指定需要获得成员变量的字段
Field f=c.getDeclaredField(“a”);
第三步:设置字段的访问权限为true
f.setAccessible(true);
第四步:创建一个对象并把这个字段值赋给这个对象
Student s=new Student();
System.out.println(f.get(s));
实现:
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class test_6 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
Class c= Student.class;
Constructor cc=c.getDeclaredConstructor();
cc.setAccessible(true);
Student s= (Student) cc.newInstance();
Field f=c.getDeclaredField("a");
f.setAccessible(true);
System.out.println(f.get(s));
}
}
控制台输出:
如果不是取值而是修改操作只需要将get方法改为set方法既可:
f.set(s,1); //将这个字段的值改为1并赋给s这个对象
System.out.println(f.get(s));
控制台输出: