概述
关于Integer一些隐藏关卡
Mackyhuang
反射绕过安全保护修改integer时候的典型错误,使用反射强行修改的时候请慎重
Integer在方法中没有提供value的get和set方法,如果现在需要你编写一个函数,使得交换俩个值,你会发现java在这里的值传递在Integer里面是copy了一个副本指向值,而不是直接地址。
那如果就是需要拥有这么一个方法的话,那么应该怎么做呢:
private static void swap(Integer a, Integer b) throws NoSuchFieldException, IllegalAccessException {
//利用反射修改
Field field = Integer.class.getDeclaredField("value");
//绕过安全检查修改final值
field.setAccessible(true);
//暂存a的值
int temp = a.intValue();
交换
field.set(a, b);
field.set(b, temp) //参数需要俩个object 所以这里会装箱
}
}
这段代码不难理解,其实就是:
int temp = a;
a = b;
b = temp
- 只不过这里是使用的反射的机制,本质还是不变的;
既然方法编写成功啦,那么我们编写一个main函数开始测试吧!
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Integer a = 1;
Integer b = 2;
System.out.println("a = " + a + ", b = " + b);
swap(a, b);
System.out.println("a = " + a + ", b = " + b);
}
-
在大家心里肯定是已经有答案了吧,不过现在的结果可能会大跌眼镜:
a = 1, b = 2 a = 2, b = 2
诶!这里为啥俩个值都会变成2呢,其实这里也是让我自己都感觉到不可思议
-
先让我们知道装箱的概念
-
如果不理解的可以看看我的另外一篇文章Java装箱和拆箱
-
现在我们再次看看valueOf这个函数
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
-
其实这里就是准备-128 到 127 缓冲区来应对高频率的整数使用
field.set(a, b);
-
问题就是出现在这一句话里面, 这里的a和b需要看main函数的初始化,不难发现他们就是由自动装箱来的,那么他们俩个其实就是
a = IntegerCache.cache[1 + -(-128)] //cache[129] b = IntegerCache.cache[2 + -(-128)] //cache[130]
那么重点来啦,现在field使用反射强行修改值,这样的操作一直都是不安全的操作,这里就是一个非常典型的例子, 这句话直接把缓冲区修改了!
cache[129] = b.intValue() // cache[129] = 2;
-
所以接下来的
field.set(b, temp)
-
这里set方法参数需要俩个object 所以这里会装箱, 也就是 temp装箱执行代码
IntegerCache.cache[temp + -(-128)] // temp = 1
-
结果已经显而易见啦!这个时候的temp装箱以后居然变成了2!所以导致了错误
看到这里已经明了了把,其实就是一句话,
使用反射修改了缓冲区,使得缓冲区完全错乱
那在进行装箱就不会有正确的结果啦,这里为了让大家更加能够理解和看到错误的缓冲区,我们再来一段代码
-
main函数声明
Integer a = 1; Integer l = 1; Integer m = 1; Integer b = 2;
-
方法中
field.set(a, b); field.set(b, new Integer(10)); field.set(3, new Integer(11)); field.set(5, new Integer(100));
-
输出缓冲区0 到 10 的元素
for (int i = 0; i <= 10; i++){ if(i % 10 == 0){ System.out.println(""); } System.out.print(i + " " + Integer.valueOf(i) + " , "); }
-
答案
0 0 , 1 2 , 2 10 , 3 11 , 4 4 , 5 100 , 6 6 , 7 7 , 8 8 , 9 9
现在很清楚了把,缓冲区被轻而易举的修改啦,所以大家要牢记不要滥用反射去修改那些java保护起来的东西,java做好的保护不让你碰其实就是怕你掉进坑了,所以使用反射的时候千万要思考周全以后再来使用
最后
以上就是俊逸裙子为你收集整理的关于Integer和反射的一个缓冲区注意事项的全部内容,希望文章能够帮你解决关于Integer和反射的一个缓冲区注意事项所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复