java反射修改泛型约束和String创建方式

一,利用反射跳过泛型约束(ArrayList)

利用反射,获取到ArrayList的add()方法,进行一个修改,使可以达到
ArrayList list; list.add(“hello”),实现一个Integer数组,可以存入字符串,或者其他数据类型,代码实现如下:

/*
    实现跳过泛型约束,add方法添加数据
 */
public class ArrayReflect {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList<Integer> list=new ArrayList<>();
//        list.add("18");会报错,需通过反射,直接跳过泛型检测
        Class<? extends ArrayList> aClass = list.getClass();
//        通过反射获取add方法并增强,使参数为Object类型的数据,在list集合字节码文件中,add方法参数有Object类型的
        Method add = aClass.getDeclaredMethod("add", Object.class);
//        忽略访问权限
        add.setAccessible(true);
//        方法执行
        add.invoke(list,"林梦豪");
        add.invoke(list,1314);
        add.invoke(list," ");
        add.invoke(list,520);
        add.invoke(list,"杨月");
        System.out.println(list);

    }
}

二,利用反射修改字符串但不改变对象指向

原理

  1. 首先,String类型的数据做修改时,对象指向会变,也就是字符串改变了,相当于new了一个新对象(当然忽略常量池)
  2. 其次,String类的创建对象时,是将数据存到 char value[]中的
  3. 利用反射获取到value[],并修改数值,既可以达到字符串修改,并且指向不变的效果
    代码和部分源码如下
   public class StringReflect {
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
       String s = "abc";
//        在不改变s的指向,输出abcd
       /*编写代码,由于String赋值是创建一个新的对象,则会改变指向,
           StringBuilder中的apend()方法可以不创建新的对象,但是构造方法是把s作为参数初始化,并没有让s后面多一个d
           这时候可以使用反射
       */
       /*
           String类构造方法源码:
             public String(String original) {
               this.value = original.value;
               this.hash = original.hash;
           }
            private final char value[];
            实质是将参数给char[]
        */
//        获取类加载
       Class<? extends String> sClass = s.getClass();
//        获取变量char[] value
       Field value = sClass.getDeclaredField("value");
//        忽略私有修饰符,直接暴力修改
       value.setAccessible(true);
       value.set(s,"abcd".toCharArray());
       System.out.println(s);
   }
}

其中,StringBuffer和StringBuilder可以实现修改字符串,指向不改变

值得一提的是String创建对象的指向问题

  1. 字符串通常有连个地方存储,一个是堆,一个是字符常量池(栈中的只是字符串指向或者说是内存地址)
  2. String s=new String("abc");这种方法创建,会创建两个对象,一个是字符串对象,存在堆中,一个是“abc”字符常量,存在字符常量池中
  3. String s="abc"这种方式,首先去看字符常量池中有无相同字符串,如果有,直接指向该常量,如果没有,则创建
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值