包装类型拆箱遇到的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. 装箱和拆箱的实现
对上面的代码进行编译,查看字节码,如图所示:
装箱的时候,使用静态的valueOf()方法;拆箱的时候,使用非静态的intValue()方法。
经过测试,上述的所有类型,装箱都会调用静态的valueOf()方法,而拆箱使用非静态xxxValue()方法。
补充知识:
来看下面的代码,会是输出什么呢?
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);
Integer是引用类型,引用类型是要看引用的地址的,很明显这四个都不是同个对象,都打印false.
然而……
这里就涉及到一个缓存的问题。查看Integer的valueOf()代码,可以看到,在某个范围内,会从缓存取值,这样取出来的,就是同一个对象了。
IntegerCache的范围一般是[-128,127]。(是否可以修改,待确认)
经检查
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;