Java 小谜题:为什么出现空指针异常? 介绍

Java 小谜题:为什么出现空指针异常? 介绍,java,nullpointerexception,puzzle,Java,Nullpointerexception,Puzzle,我被这个问题耽误了几分钟。所以,它可能会帮助其他人,这是一个有趣的错误。但解决了第一个问题,我又想到了另一个问题 第一个难题: 考虑以下代码: public void setValue(ValueWrapper valueWrapper) { if (anotherValueWrapper == null) { anotherValueWrapper = new AnotherValueWrapper(); } ano

我被这个问题耽误了几分钟。所以,它可能会帮助其他人,这是一个有趣的错误。但解决了第一个问题,我又想到了另一个问题


第一个难题: 考虑以下代码:

public void setValue(ValueWrapper valueWrapper) {

        if (anotherValueWrapper == null) {
            anotherValueWrapper = new AnotherValueWrapper();
        }

        anotherValueWrapper.setValue(valueWrapper == null ? null : valueWrapper.getValue());
    }
事实:

public void setValue(ValueWrapper valueWrapper) {

        if (anotherValueWrapper == null) {
            anotherValueWrapper = new AnotherValueWrapper();
        }

        anotherValueWrapper.setValue(valueWrapper == null ? null : valueWrapper.getValue());
    }
  • 这段代码编译
  • getter和setter是标准(只返回字段或设置字段)
问题

在执行过程中,有一种情况是代码失败并返回空指针异常

第一个难题是:此代码何时会导致NullPointerException?

不要看第二个问题,因为如果你没有找到第一个问题,它就是一个破坏者


第二个问题 好的,您会发现(或者可能不会):问题是当另一个ValueWrapper像这样编写时:

public class AnotherValueWrapper {
  private long value;

  public long getValue() { return value; }

  public void setValue(long value) { this.value = value; }
}
和ValueWrapper:

public class ValueWrapper {
  private Long value;

  public Long getValue() { return value; }

  public void setValue(Long value) { this.value = value; }
}
第二个问题来了:

如果我写:

anotherValueWrapper.setValue(null);

由于
另一个ValueWrapper.setValue
采用原语(long)而非
long
(对象),if无法编译

但该代码编译:

anotherValueWrapper.setValue(valueWrapper == null ? null : valueWrapper.getValue());

为什么?

因为
Long
String
是不可交换的,但是
Long
null
是可交换的

anotherValueWrapper.setValue(null);
无法编译,因为无法将基元设置为null。另一个ValueWrapper对“value”字段使用long(原语)

anotherValueWrapper.setValue(valueWrapper == null ? "test": valueWrapper.getValue());
不编译,因为“test”是一个字符串,因此无法分配给长变量。

With

anotherValueWrapper.setValue(valueWrapper == null ? null : valueWrapper.getValue());
null
实际上属于
Long
类型,它尝试自动装箱到
Long
,因此在执行setValue(null)或setValue(“test”)时抛出空指针异常

,它显式地传入一个对象和一个字符串类,而它们与基本类型Long不匹配


但是,传入对象类型Long是可以的,因为Java的自动装箱特性可以在原语类型和对象包装器之间自动转换。将Long对象传入另一个ValueWrapper的setValue()方法时,它会在引擎盖下执行Long的longValue()方法,如果Long对象为null,则会导致NullPointerException。

事实上,另一个ValueWrapper.setValue使用Long(原语)而不是Long(对象)所以奇怪的是,当使用这种语法时,编译器无法检测到这样一个空值