6

如果您运行以下代码,

public class Foo{
    public static void main(String[] args){
        int id = new Bar().getId(); // throws unexpected NullPointerException
    }

    private static class Bar{
        private final Integer id;

        public Bar(){
            this(null);
        }

        public Bar(Integer id){
            this.id = id;
        }

        public Integer getId(){
            return id;
        }
    }
}

您将获得以下堆栈跟踪,

Exception in thread "main" java.lang.NullPointerException
    at Foo.main(Foo.java:3)

为什么没有编译器警告或任何东西?恕我直言,拆箱是一个非常令人讨厌的微妙之处,或者我可能只是天真。


除了@Javier提供的答案之外,如果您使用的是 Eclipse,则需要执行以下操作才能启用此功能:

  1. 导航到Window> Preferences> Java> Compiler>Errors/Warnings
  2. 展开潜在的编程问题
  3. 将装箱和拆箱转换切换为“警告”或“错误”
  4. 点击“确定”
4

6 回答 6

6

我不知道您使用的是什么 IDE,但 Eclipse 有一个选项可以启用对装箱和拆箱转换的警告。不可能将其检测为空指针访问,因为 null 不是立即拆箱的,而是通过Bar.getId().

Integer 类型的表达式被拆箱到 int
Foo.java 第 3 行

于 2013-02-20T23:49:49.757 回答
6

如果您尝试在 a 上使用任何方法null或做任何对 a 没有意义的事情null,它会抛出 a NullPointerException

自动拆箱是使用[Integer object].intValue()方法(或类似方法)实现的,因此它会抛出 aNullPointerException因为您不能null调用方法。

希望这可以帮助!

于 2013-02-20T23:54:12.463 回答
5

JDK™ 5.0 文档中似乎记录了此行为,

int..您可以在很大程度上忽略and之间的区别Integer,但有一些警告。表达式可以有一个Integer空值。如果你的程序试图自动拆箱 null,它会抛出一个NullPointerException.

于 2013-02-24T03:53:20.857 回答
0

NullPointerException是一个RuntimeException比IDE在编译代码时无法检测到的问题。

相反,一个好的做法是在取消装箱之前检查 null。

int getId(){
    if(id!=null){
        return id;
    }
    // return other or throw a checked exception.
}
于 2013-02-20T23:58:20.790 回答
0

似乎是一个完全合理的运行时异常。如果您的主要代码是:

public static void main(String[] args){        
    Integer idObj = new Bar().getId();
    int id = idObj;   // throws NullPointerException
}

没有人会对空指针异常感到惊讶。Bar 类返回一个空值,空对象指针不能转为简单值。Bar 类的实现可能会更改为将 id 初始化为非空值。这段代码可以独立于 Bar 类进行编译,因此关于 Bar 类的动态工作的假设当然不应该被编码到这段代码中。

这可能很明显,但真正的解决方案是使用intid 成员,而不是Integer. 那么,这没有问题:

private static class Bar{
    private final int id;

    public Bar(){
        this(0);
    }

    public Bar(int id){
        this.id = id;
    }

    public int getId(){
        return id;
    }
}

(但我想你已经意识到了这一点:-))

于 2013-02-21T00:05:23.533 回答
0

装箱只不过是将像 Integer 这样的对象转换为原生等效的“int”的语法糖。本机不能为空,但对象可以。在这些情况下,装箱机制不会阻止 NullPointerExceptions。

于 2013-02-24T04:15:43.003 回答