包装类型拆箱遇到的Bug-NullPointException

现在还在加班的一只猿,调用公司现有的流程的时候遇到了一个NullPointException,照理来说这种问题一看日志就能定位到问题,但是这次花了我好一会才定位问题,首先报错的代码:

sv.mergeToHis(obj, new TableDeterminerImpl(in.getMerge().getRunId(), in.getTableSubfix()),  // 日志这一行报错了
                                runId, in.getMerge().getRunId(), in.getMerge().getFields(), share.getArgs());
直接说原因吧:
in.getMerge().getRunId() //   是个空的Long 类型
TableDeterminerImpl(long id, String tableSubfix)  构造函数id是个long类型

拆箱的时候出现了空指针的异常,至于为什么,和拆箱和装箱的底层实现有关。

null 与 对象的转换

null既不是对象也不是一种类型,它仅是一种特殊的值,你可以将其赋予任何引用类型,你也可以将null转换成任何类型。例如下面的代码,是可以运行的。

关于null的知识点,可以参考 Java中有关Null的9件事

Integer a = (Integer) null;
Double b = (Double) null;
Boolean c = (Boolean) null;

装箱:基本类型->包装器类型;拆箱:包装器类型->基本类型。

1 Integer integer = 1; //装箱
2 int i = integer; //拆箱

3. 装箱和拆箱的实现

对上面的代码进行编译,查看字节码,如图所示:

包装类型拆箱遇到的Bug-NullPointException

装箱的时候,使用静态的valueOf()方法;拆箱的时候,使用非静态的intValue()方法。

经过测试,上述的所有类型,装箱都会调用静态的valueOf()方法,而拆箱使用非静态xxxValue()方法。

补充知识:

来看下面的代码,会是输出什么呢?

包装类型拆箱遇到的Bug-NullPointException
1 Integer a = 1;
2 Integer b = 1;
3 Integer c = 200;
4 Integer d = 200;
5 System.out.println(a == b);
6 System.out.println(c == d);
包装类型拆箱遇到的Bug-NullPointException

Integer是引用类型,引用类型是要看引用的地址的,很明显这四个都不是同个对象,都打印false.

然而……

包装类型拆箱遇到的Bug-NullPointException

这里就涉及到一个缓存的问题。查看Integer的valueOf()代码,可以看到,在某个范围内,会从缓存取值,这样取出来的,就是同一个对象了。

包装类型拆箱遇到的Bug-NullPointException

 IntegerCache的范围一般是[-128,127]。(是否可以修改,待确认)

包装类型拆箱遇到的Bug-NullPointException

经检查

1)Integer, Byte, Long, Short都是从[-128, 127];Character是[0,127];Boolean是FALSE or TRUE.

2)Double和Float没有缓存的概念

3)通过直接创建的对象,不会从缓存中获取。

1 Integer a = new Integer(1);
2 Integer b = new Integer(1);
3 System.out.println(a == b);

打印false;

包装类型拆箱遇到的Bug-NullPointException

上一篇:LeetCode剑指offer二叉树系列


下一篇:go测试跨包代码覆盖率