当前位置: 首页 > 科技观察

一段代码打断Java,坑埋在胸口!

时间:2023-03-15 15:45:33 科技观察

本文转载自微信公众号“小姐姐的味道”,作者小姐姐养的狗。转载本文请联系味觉小姐公众号。数字计算是语言的基础。如果连1+1都变得不可信,那么整个程序都会变得不可信。考虑这样一段代码:Integera=1;System.out.println(a);Integerb=2;System.out.println(a.intValue()==b.intValue());System.out.println(等于(b));执行结果竟然是:-996truetrue这个时候你还敢继续写代码吗?为什么会这样?很简单,我们用反射来改变一些东西。下面这段代码会改变一些基本操作的执行逻辑,当然属于埋坑的范畴。我们先来看看它的行为。publicclassStaticBlock{static{try{Classcls=Integer.class.getDeclaredClasses()[0];Fieldf=cls.getDeclaredField("cache");f.setAccessible(true);Integer[]cache=((Integer[])f.get(cls));for(inti=0;i=IntegerCache.low&&i<=IntegerCache.high)returnIntegerCache.cache[i+(-IntegerCache.low)];returnnewInteger(i);}为了提高转换效率,里面缓存了Integeri和Integer的对应关系!这样下次使用的时候,直接定位就可以了。缓存变量是存储这些中间信息的地方。如果我们通过反射改变它,Integer就会有异常行为!更多的IntegerCache,在low和high之间缓存Integer对象,可以通过-XX:AutoBoxCacheMax修改。StringintegerCacheHighPropValue=sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");有意思的是,Long也有这样的Cache,只不过它的上下限是固定的,Byte和Short也是一样的。staticfinalLongcache[]=newLong[-(-128)+127+1];SDouble和Float比较差,只能直接new一个,做不了这种缓存。总的来说,Integer还是比较特别的。下面这段代码,即使我们不做反射魔改,它的输出还是不确定的。Integern1=123;Integern2=123;Integern3=128;Integern4=128;System.out.println(n1==n2);System.out.println(n3==n4);这是因为,一般情况下,它会输出true、false;而当我们使用AutoBoxCacheMax增加它的上限时,它会输出true,true。果然,对象之间的比较,还是要用equals,相对靠谱些。恩德看着这个齐胸的洞,心里的心情真是无法言喻。整体看这段代码,如果正常review的话,还是很容易看出问题的,但总有不对的地方。如果把这段代码放到网上,即使是可爱的同学在练习的时候不小心提交到了仓库,后果也是不堪设想的。这段代码的目的比较简单,但是如果我们把缓存数组的修改逻辑复杂一点,只在特定条件下触发单个变量值的修改,那将是致命的。毕竟连sonar都扫描不出来,而且jdk里面还有很多私有变量等着我们去挖掘!作者简介:品味小姐姐(xjjdog),一个不允许程序员走弯路的公众号。专注于基础架构和Linux。十年架构,每天百亿流量,与你探讨高并发世界,给你不一样的滋味。

猜你喜欢