Java 反射越过泛型检查和暴力反射

越过泛型检查

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));

控制台输出:
在这里插入图片描述

Java 中,泛型是通过类型擦除来实现的,这意味着在运行时,泛型信息会被擦除,只剩下原始类型。因此,直接通过反射越过泛型检查是不可能的。不过,你可以通过一些技巧来绕过泛型检查并实现泛型擦除。下面是一种常见的方法: 1. 获取泛型字段或方法的签名: ```java Field field = YourClass.class.getDeclaredField("yourField"); Type fieldType = field.getGenericType(); ``` 或者 ```java Method method = YourClass.class.getDeclaredMethod("yourMethod"); Type returnType = method.getGenericReturnType(); ``` 2. 使用 `ParameterizedTypeImpl` 类来创建一个新的带有原始类型参数的泛型类型: ```java ParameterizedType genericType = (ParameterizedType) fieldType; Type[] typeArguments = genericType.getActualTypeArguments(); Type rawType = genericType.getRawType(); Type newType = ParameterizedTypeImpl.make(rawType, typeArguments, null); ``` 3. 使用新的泛型类型来访问字段或方法: ```java field.set(obj, newType); ``` 或者 ```java Object result = method.invoke(obj); ``` 这种方法可以绕过编译器对泛型的检查,但请注意,这可能会导致类型安全问题。使用这种方法时,请确保你对类型进行了正确的处理,并且清楚你在做什么。 需要注意的是,以上代码只是一个示例,具体实现可能因你的需求和代码结构而有所不同。同时,这种绕过泛型检查的方法并不被推荐使用,因为它可能导致运行时错误和类型不一致。建议在编码时尽量遵循泛型的规范和约束,避免使用反射越过泛型检查。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值