Java解引用抛出NPE的几个场景分析

Posted by huangliangliang on June 30, 2016

Null Point Exception的问题在java中一直都是难定位,头疼的问题。对java语言默认解引用的了解,可以更好地定位代码逻辑中出现的问题。

以下整理了下Java里的一些操作隐含对引用的解引用:

  • 读字段(字节码 getfield):x.y,当x为null时抛NPE;

  • 写字段(字节码 putfield):x.y = z,当x为null时抛NPE。注意:z的值是什么没关系;

  • 读数组长度(字节码 arraylength):a.length,当a为null时抛NPE;

  • 读数组元素(字节码 aload,为类型前缀):a[i],当a为null时抛NPE;

  • 写数组元素(字节码 astore,为类型前缀):a[i] = x,当a为null时抛NPE。注意:x的值时什么没关系;

  • 调用成员方法(字节码 invokevirtual、invokeinterface、invokespecial):obj.foo(x, y, z),当obj为null时抛NPE。注意:参数的值是什么没关系;
  • 增强for循环(也叫foreach循环):
  • 对数组时(实际隐含a.length操作):for (E e : a) { … } , 当a为null时抛NPE;
  • 对Iterable时(实际隐含对Iterable.iterator()的调用):for (E e : es) { … } ,当es为null时抛NPE;
  • 自动拆箱(实际隐含 .Value() 的调用,为包装类型名,为对应的原始类型名): (int) integerObj,当integerObj为null时抛NPE;
  • 对String做switch(实际隐含的操作包含对String.hashCode()的调用):switch (s) { case “abc”: … } ,当s为null时抛NPE;
  • 创建内部类对象实例(字节码 new,但这里特指创建内部类实例的情况):outer.new Inner(x, y, z),当outer为null时抛NPE;
  • 抛异常(字节码 athrow):throw obj,当obj(throw表达式的参数)为null时抛NPE;
  • 用synchronized关键字给对象加锁(字节码 monitorenter / monitorexit):synchronized (obj) { … },当obj为null时抛NPE。