为什么java在使用未初始化的变量时会不同地处理类范围和方法范围?

时间:2012-07-23 12:11:33

标签: java initialization scope

Java不允许您使用可能尚未在方法范围内初始化的变量。类范围内的未初始化变量仍可由类方法返回,值默认为null。

为什么对两种不同范围的不同处理?

public class TestClass {

    Integer i;
    Double d;

    public TestClass() {
        d = 1d;
    }

    public Double getD() {
        return d;
    }

    public Integer getI() {
        return i;
    }

//  public Integer getSomeInt() {
//      Integer i;
//      return i;
//  }

    public static void main(String[] args) {
        TestClass myClass = new TestClass();
        System.out.println(myClass.getI().getClass());
    }
}

这导致NullPointerException,但是在getSomeInt()中返回i是编译器错误,因为“该变量可能尚未初始化”。

4 个答案:

答案 0 :(得分:3)

这背后的原因是Java静态代码分析的局限性。编译器能够毫无疑问地证明在初始化之前不会读取堆栈分配的局部变量。这对于堆分配的内存是不可能的,因此Java要求在暴露指向它的指针之前将所有堆分配的存储清零。

此规则的结果是所有堆分配的默认值都为零(false,null,无论该类型的二进制零值是多少)。

答案 1 :(得分:2)

因为成员变量具有默认值(如果未初始化),因此I具有null,如果您在null上调用方法,则会导致NullPointerException

对于局部变量,必须先使用它们进行初始化,否则会变成编译时错误

  

局部变量略有不同;编译器永远不会为未初始化的局部变量分配默认值。如果无法初始化声明它的局部变量,请确保在尝试使用它之前为其赋值。访问未初始化的局部变量将导致编译时错误。 [....]

答案 2 :(得分:1)

真的很简单。成员变量会自动初始化为默认值,而局部变量则不会。

当你这样做时

public Integer getSomeInt() {
    Integer i;
    return i;
}

隐藏 this.i并在return i中引用(未初始化的)本地变量。


所以为什么是自动初始化的成员变量,而局部变量不是?

最终这是一个问题,只有语言的设计者才能回答,但如果我不得不猜测我会说这是由于必须将所有内存分配的性能问题。当涉及到对象时,强制程序员明确初始化所有字段将是一种痛苦。


来自JLS(4.12.3种变量):

  

在准备类或接口(第12.3.2节)和时,会创建一个类变量   被初始化为默认值(§4.12.5)。

     

[...]

     

局部变量声明语句可能包含一个表达式   初始化变量。具有初始化表达式的局部变量是   但是,没有初始化,直到局部变量声明语句为止   声明它被执行。 (明确赋值的规则(第16章,定义   赋值)防止局部变量的值在它之前被使用   已初始化或以其他方式分配值。)

答案 3 :(得分:0)

在调用super之后但在其他任何内容之前,所有字段都在构造函数中隐式初始化。对象引用设置为null,原始值设置为0false等。 这种隐式初始化不是在方法中完成的。