Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中未初始化的变量和成员_Java_Oop_Variables - Fatal编程技术网

Java中未初始化的变量和成员

Java中未初始化的变量和成员,java,oop,variables,Java,Oop,Variables,考虑这一点: public class TestClass { private String a; private String b; public TestClass() { a = "initialized"; } public void doSomething() { String c; a.notify(); // This is fine b.notify(); // This is

考虑这一点:

public class TestClass {

    private String a;
    private String b;

    public TestClass()
    {
    a = "initialized";
    }

    public void doSomething()
    {
    String c;

        a.notify(); // This is fine
    b.notify(); // This is fine - but will end in an exception
    c.notify(); // "Local variable c may not have been initialised"
    }

}
我不明白。“b”从未初始化,但将给出与“c”相同的运行时错误,这是一个编译时错误。为什么局部变量和成员之间存在差异


编辑:将成员私有化是我最初的意图,问题仍然存在……

编译器可以发现永远不会设置c。在调用构造函数之后,但在doSomething()之前,其他人可以设置b变量。将b设为private,编译器可能会提供帮助。

编译器可以从doSomething()的代码中看出c在那里声明,并且从未初始化过。因为它是本地的,所以不可能在其他地方初始化


它无法告诉您将在何时何地调用doSomething()。b是公共会员。在调用该方法之前,完全有可能在其他代码中对其进行初始化。

该语言是这样定义的

对象类型的实例变量默认初始化为null。 默认情况下,对象类型的局部变量未初始化,访问未定义的变量是编译时错误

SE7见第4.12.5节(与SE14相同)

事情是这样的。当你打电话的时候

TestClass tc = new TestClass();
new
命令执行四项重要任务:

  • 在堆上为新对象分配内存
  • 将类字段初始化为其默认值(数值为0,布尔值为
    false
    ,对象为
    null
  • 调用构造函数(构造函数可能会重新启动字段,也可能不会)
  • 返回对新对象的引用
  • 因此,字段“a”和“b”都被初始化为
    null
    ,并且“a”在构造函数中被重新初始化。此过程与方法调用无关,因此局部变量“c”从未初始化


    PS:对于严重失眠症患者,请阅读。

    明确指定的规则相当困难(请阅读JLS第三版第16章)。在字段上强制执行确定赋值是不实际的。目前,甚至可以在初始化最终字段之前观察它们。

    成员变量被初始化为null或默认的基本值(如果它们是基本值)

    局部变量未定义且未初始化,您负责设置初始值。编译器阻止您使用它们

    因此,当类TestClass被实例化而c未定义时,b被初始化


    注意:null不同于未定义。

    实际上,您已经发现了Java系统中的一个较大漏洞,即通常试图在编辑/编译时而不是运行时查找错误,因为正如公认的答案所说,很难判断b是否已初始化

    有一些模式可以解决此缺陷。首先是“默认为最终”。如果您的成员是final,那么您必须用构造函数填充它们——它将使用路径分析来确保每个可能的路径都填充final(您仍然可以将其指定为“Null”,这将不符合目的,但至少您会被迫承认您是故意这样做的)

    第二种方法是严格的空检查。您可以在eclipse设置中按项目或默认属性打开它。我相信这会迫使您在调用b.notify()之前对其进行null检查。这可能会很快失控,因此它倾向于使用一组注释来简化操作:

    注释可能有不同的名称,但在概念上,一旦启用严格的null检查,并且注释的变量类型为“null”和“NotNull”。如果您试图将Nullable放入NOTNULL变量中,则必须首先检查它是否为null。参数和返回类型也带有注释,所以您不必每次分配给NOTNULL变量时都检查null

    还有一个“NotNullByDefault”包级注释,它将使编辑器假设任何变量都不能有null值,除非您将其标记为可为null


    这些注释主要应用于编辑器级别——您可以在eclipse和其他编辑器中打开它们——这就是它们不一定标准化的原因。(至少上次我检查时,Java 8可能有一些我还没有找到的注释)

    没有,即使它是私有的,编译器也不会给出错误(反正不是我的)。同样的,私有化并不重要SE 7的相应部分是4.12.5()“甚至可以在初始化最终字段之前观察它们。”-你介意再解释一下吗?Thanks@Nathan-您可以在对象的构造函数调用中引用默认状态下的“blank”
    final
    字段,以及从构造函数调用的任何内容。(和其他线程,如果构造线程“发布”实例引用。)JLS 12.4.1中解释的
    静态
    变量也会出现类似问题。(这完全超出了本问答的范围)注意:对于类型为基元类型的字段,也会发生类似的情况。