Java:为什么我需要初始化原始类型的局部变量?

30
public class Foo {
    public static void main(String[] args) {
        float f;
        System.out.println(f);
    }
}

print语句导致以下编译时错误,

局部变量f可能未被初始化

如果Java中的基本类型已经有默认值(float=0.0f),为什么还需要定义一个?


编辑:

因此,这有效。

public class Foo {
    float f;
    public static void main(String[] args) {
        System.out.println(new Foo().f);
    }
}

谢谢大家!


6
关于编辑:是的,那样可以,但是晋升一个本地变量来避免初始化可能不是一个合理的例子 :-) - fvu
1
@fvu,这只是一个例子,所以它有一定的用途。 :D - user1329572
5个回答

53

因为它是一个局部变量。这就是为什么没有给它分配任何值:

局部变量有些不同;编译器从不给未初始化的局部变量分配默认值。如果您无法在声明时初始化局部变量,请确保在使用它之前为其赋值。访问未初始化的局部变量将导致编译时错误。

编辑:为什么Java会引发编译错误? 如果我们查看IdentifierExpression.java类文件,我们会找到这个代码块:

...
if (field.isLocal()) {
            LocalMember local = (LocalMember)field;
            if (local.scopeNumber < ctx.frameNumber && !local.isFinal()) {
                env.error(where, "invalid.uplevel", id);
            }
            if (!vset.testVar(local.number)) {
                env.error(where, "var.not.initialized", id);
                vset.addVar(local.number);
            }
            local.readcount++;
        }
...

如所述 (if (!vset.testVar(local.number)) {),JDK使用testVar检查变量是否被分配了(Vset的源代码中可以找到testVar代码)。如果未被分配,则会从属性文件引发错误var.not.initialized:

...
javac.err.var.not.initialized=\
    Variable {0} may not have been initialized.
...

来源


3
这并没有真正“解释”“为什么”,是吗? - kryger

18

实际上,编译器 不会 为您的 float f 分配默认值,因为在这种情况下它是一个局部变量而不是字段:

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


8

类字段(除了final字段)会被初始化为默认值,而局部变量则不会。

在声明字段时,不总是需要赋值。如果声明但未初始化的字段,编译器会将其设置为合理的默认值。

因此,在以下代码中,像f这样的(非final)字段

class C {
  float f;
}

0f将被初始化,但本地变量f

void myMethod() {
  float f;
}

不会。

语言对待本地变量与字段的方式不同。本地变量具有良好的作用域生命周期,因此在初始化之前的任何使用都可能是错误的。而字段则没有这样的生命周期限制,因此默认初始化通常很方便。


5

实际上,局部变量存储在堆栈中。因此,存在获取局部变量之前的旧值的可能性。出于安全原因,这是一个巨大的挑战。因此,Java要求在使用局部变量之前进行初始化。


2

大家好,解决方案很简单。 在堆内存中存储的值是根据数据类型由编译器初始化的,但是局部变量存储在堆栈内存中,因此我们必须显式地初始化它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接