代码之家  ›  专栏  ›  技术社区  ›  Roman

为什么在Java中比较Integer和int会引发NullPointerException?

  •  72
  • Roman  · 技术社区  · 16 年前

    观察这种情况让我非常困惑:

    Integer i = null;
    String str = null;
    
    if (i == null) {   //Nothing happens
       ...                  
    }
    if (str == null) { //Nothing happens
    
    }
    
    if (i == 0) {  //NullPointerException
       ...
    }
    if (str == "0") { //Nothing happens
       ...
    }
    

    所以,正如我认为装箱操作是首先执行的(即java试图从中提取int值) null )比较操作的优先级较低,这就是引发异常的原因。

    无效的 在拳击之前?

    NullPointerException 是的 对象类型。

    6 回复  |  直到 15 年前
        1
  •  139
  •   Community Mohan Dere    6 年前

    简短的回答

    关键是:

    • == 两种引用类型之间总是引用比较
      • Integer String ,你想用 equals 相反
    • == 引用类型和数值基元类型之间始终是数值比较
      • 引用类型将进行拆箱转换
      • 拆箱 null 总是抛出 NullPointerException
    • 字符串 ,它实际上不是一个基元类型

    有效的


    长话短说

    以下是相关的JLS部分:

    JLS 15.21.3 Reference Equality Operators == and !=

    如果相等运算符的操作数都是引用类型或

    这说明了以下问题:

    Integer i = null;
    String str = null;
    
    if (i == null) {   // Nothing happens
    }
    if (str == null) { // Nothing happens
    }
    if (str == "0") {  // Nothing happens
    }
    

    两个操作数都是引用类型,这就是 == 是引用等式比较。

    System.out.println(new Integer(0) == new Integer(0)); // "false"
    System.out.println("X" == "x".toUpperCase()); // "false"
    

    为了 == 至少有一个操作数必须是数字类型

    JLS 15.21.1 Numerical Equality Operators == and !=

    如果相等运算符的操作数是 数字类型,或 数字类型和 另一辆是敞篷车 对于数字类型,对操作数执行二进制数字提升。如果操作数的提升类型为 int long ,然后进行整数相等性检验;如果升级类型为 float or

    请注意,二进制数字提升执行值集转换和取消装箱转换。

    这说明:

    Integer i = null;
    
    if (i == 0) {  //NullPointerException
    }
    

    下面是一个节选自 有效Java第2版,第49项:首选原语而不是装箱原语 :

    == 运算符,它进行身份比较,这几乎肯定不是您想要的。当您的程序执行包含装箱和未装箱原语的混合类型计算时,它执行取消装箱,当您的程序执行取消装箱时,它可以抛出 空指针异常 . 最后,当您的程序装箱原始值时,可能会导致昂贵和不必要的对象创建。

    在有些地方,您别无选择,只能使用装箱原语,例如泛型,否则您应该认真考虑使用装箱原语的决定是否合理。

    工具书类

    相关问题

        2
  •  15
  •   Alexander Pogrebnyak    16 年前

    您的NPE示例与此代码等效,这要感谢 自动包装 :

    if ( i.intValue( ) == 0 )

    因此,如果 i null

        3
  •  4
  •   Damian Leszczyński - Vash    16 年前
    if (i == 0) {  //NullPointerException
       ...
    }
    

    我是一个整数,0是一个整数,所以在这个例子中,真正要做的事情是这样的

    i.intValue() == 0
    

    这会导致空指针,因为i是空的。对于String我们没有这个操作,这就是为什么没有例外。

        4
  •  4
  •   supercat    12 年前

    Java的制造者可以定义 == 运算符直接作用于不同类型的操作数,在这种情况下 Integer I; int i; I==i; 可以问一个问题“是吗 I 保留引用 Integer 谁的价值是 i ?“——一个即使在 为空。不幸的是,Java不能直接检查不同类型的操作数是否相等;相反,它检查语言是否允许将其中一个操作数的类型转换为另一个操作数的类型,如果允许,则将转换后的操作数与未转换的操作数进行比较。这样的行为意味着对于变量 x , y z 有了一些类型的组合,就有可能 x==y y==z 但是 x!=z [例如,x=16777216f y=16777216 z=16777217]。这也意味着 I==i 翻译成“把我变成一个 int 如果没有抛出异常,请将其与 ."

        5
  •  1
  •   Christian Seifert    16 年前

    这是因为Javas 自动包装 功能。编译器检测到,在比较的右侧,您正在使用一个基元整数,并且需要将包装器整数值解装箱为一个基元int值。

    因为这是不可能的(它是空的,因为你列出来)的 NullPointerException 被抛出。

        6
  •  1
  •   Joachim Sauer    16 年前

    i == 0 Java将尝试进行自动拆箱并进行数值比较(即“是否存储在包装器对象中的值被 i 0 ?").

    null NullPointerException .

    推理是这样的:

    第一句话 JLS § 15.21.1 Numerical Equality Operators == and != 读起来像这样:

    很明显 0 是数字类型,因此对操作数执行二进制数字提升。

    § 5.6.2 Binary Numeric Promotion

    如果任何操作数是引用类型,则取消装箱转换(§5.1.8)执行。

    § 5.1.8 Unboxing Conversion

    如果 如果为null,取消装箱转换将引发 空指针异常

        7
  •  0
  •   Satish Hawalppagol    5 年前

    public static Integer getNotNullIntValue(Integer value)
    {
        if(value!=null)
        {
            return value;
        }
        return 0;
    }