一个由泛型和Auto Unbox引发的Crash

来源:互联网 发布:有关大数据的例子 编辑:程序博客网 时间:2024/04/30 10:27

出了个神奇的Crash,复盘一下:
public boolean foo(HashMap<String, Boolean> map){
...
return null != map && map.get("a_key");
}

这段代码居然有空指针,出在最后一行。这个空指针的原因还是很神奇的。
当“a_key”不在map中时,map会返回null。按照本屌的理解,实际调用的流程应该是:
boolean first = null != map;
if(first){
Object second = map.get("a_key"); //泛型里,类型擦除了
if(second instanceof Boolean){
return Boolean.valueOf(second);
}
}

实际上,大JVM的字节码是这样的:
...
#3 = Class #34 // java/lang/Boolean
...
21: invokevirtual #8 // Method java/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;实际上真的是get了一个Object!果然是擦除了!
24: checkcast #3 // class java/lang/Boolean 貌似只有泛型的字节码里有这个调用,貌似,貌似
27: invokevirtual #9 // Method java/lang/Boolean.booleanValue:()Z 直接在get到的Object上invoke booleanValue!!!!!!所谓的auto unbox

擦除仅仅是在get的时候,检查了类型之后,直接将拿到的Object当做泛型对象使用,调用其上的booleanValue方法。这样就会有null.booleanValue()的调用出现,抛出空指针。
注意:Boolean.valueOf(obj)是不能解决这个问题的,因为get出来的对象会为了符合函数参数类型,进行一次unbox。

最后解决的办法:
Boolean val = null != map && map.get("a_key");//有checkcast,没有unbox
return null != val && val;//Boolean对象是可以为空的

Java字节码参考1 参考2

0 0
原创粉丝点击