Java 装箱与拆箱相关的空指针问题

问:下面代码片段 func1 与 func2 在被调用时会如何执行?简单分析下原因?
public class Test {
    public void func1() {
        if ((Integer) null > 1) {}
    }

    public void func2() {
        if ((Integer) null > 1) {
            System.out.println("ABCDEFG");
        }
    }
}

答:上面代码段 func1、func2 在调用时都会抛出 NullPointerException 空指针异常。具体原因我们可以通过 javap 看编译后的 class 字节码,如下:

#javap -c Test
Compiled from "Test.java"
public class Test {
  ......
  public void func1();
    Code:
       0: aconst_null
       1: checkcast     #5    // class java/lang/Integer
       4: invokevirtual #6    // Method java/lang/Integer.intValue:()I
       7: iconst_1
       8: if_icmple     11
      11: return

  public void func2();
    Code:
       0: aconst_null
       1: checkcast     #5    // class java/lang/Integer
       4: invokevirtual #6    // Method java/lang/Integer.intValue:()I
       7: iconst_1
       8: if_icmple     19
      11: getstatic     #7    // Field java/lang/System.out:Ljava/io/PrintStream;
      14: ldc           #8    // String ABCDEFG
      16: invokevirtual #9    // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      19: return
}

可以看到,作用在包装类型上的二元运算符会导致拆箱操作,拆箱的实质是调用包装类型对象的 intValue 方法,所以会抛出 NullPointerException 问题。

而 == 和 != 二元运算符在包装类型中比较特殊,需要区别对待,包装类型和基本类型进行 == 或者 != 运算时包装类型会自动拆箱变为基本型后再进行比较,而两个包装类型进行 == 或者 != 比较的是对象地址。具体变换案例如下:

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        test.func1();
        test.func2();
    }

    //运行成功,if判断为 false
    public void func1() {
        if ((Integer) null == new Integer(1)) {}
    }

    //运行崩溃,NullPointerException 问题
    public void func2() {
        if ((Integer) null == 1) {
            System.out.println("ABCDEFG");
        }
    }
}
问:下面语句能正常执行吗?
Integer test1 = (Integer) null;
Double test2 = (Double) null;
Boolean test3 = (Boolean) null;

答:上面语句可以正常执行。因为在 java 中 null 既不是对象也不是一种类型,它仅是一种特殊的值,我们可以将其赋予任何引用类型,也可以将 null 转化成任何类型。

本文参考自 Java 装箱与拆箱相关的空指针陷阱题解析

你可能感兴趣的:(Java 装箱与拆箱相关的空指针问题)