【问题标题】:Java variable may not have been initializedJava 变量可能尚未初始化
【发布时间】:2014-06-02 22:31:59
【问题描述】:

我正在从事 Project Euler Problem 9,其中指出:

毕达哥拉斯三元组是三个自然数的集合,a

a^2 + b^2 = c^2

例如,3^2 + 4^2 = 9 + 16 = 25 = 52。

恰好存在一个毕达哥拉斯三元组,其 a + b + c = 1000。 找到产品 abc。

这是我到目前为止所做的:

class Project_euler9 {

    public static boolean determineIfPythagoreanTriple(int a, int b, int c) {
        return (a * a + b * b == c * c);
    }   

    public static void main(String[] args) {
        boolean answerFound = false;
        int a, b, c;
        while (!answerFound) {
            for (a = 1; a <= 1000; a++) {
                for (b = a + 1; b <= 1000; b++) {
                    c = 1000 - a - b;
                    answerFound = determineIfPythagoreanTriple(a, b, c);
                }
            }
        }
        System.out.println("(" + a + ", " + b + ", " + c + ")");
    }
}

当我运行我的代码时,我得到了这个错误:

Project_euler9.java:32: error: variable a might not have been initialized
        System.out.println("The Pythagorean triplet we're looking for is (" + a + ", " + b + ", " + c + ")");

注意:我为每个变量(a、b 和 c)都得到了这个,只是行号不同。

我认为当我将 a、b 和 c 声明为整数时,如果未赋值,则默认值为 0。

即使不是这样,在我看来他们都确实被分配了,所以我对这个错误有点困惑。

为什么会这样?

【问题讨论】:

  • 除了 Oscar 写的内容之外,还有没有意义的 while 循环,因为在 for 循环完成之前你没有检查它 (answerFound)...

标签: java initialization


【解决方案1】:

实例变量(在您的情况下,它们将是整数)默认分配给0。局部变量不是(From Java Docs)

如果没有进入循环,那么你的变量不会被初始化,这就是错误的原因。

你可以做的是在声明时初始化它们

int a=0, b=0, c=0;

【讨论】:

    【解决方案2】:

    你的问题是这一行:

    System.out.println("(" + a + ", " + b + ", " + c + ")");
    

    while (!answerFound) {...} 循环之后。编译器认为可能存在一个或多个变量abc 未初始化的情况。

    使用这一行:

    int a=0, b=0, c=0;
    

    在声明变量时,使它们在声明时被初始化,并且错误应该消失。

    【讨论】:

      【解决方案3】:

      在声明局部变量后的方法开头这样做:

      a = b = c = 0;
      

      该错误基本上表明Java无法确定变量到达System.out.println()时是否具有分配的值。请记住:在 Java 中只有属性具有默认值,所有局部变量都必须在某个时候显式初始化。

      【讨论】:

        【解决方案4】:

        你的想法是对是错:

        你是对的:

        • 是的,编译器可能会为未初始化的变量赋值,但是 a) 它被认为是不好的风格,b) 你不应该依赖它,c) 这不适用于局部变量(如在方法中声明的) )

        你错在哪里:

        • 没有为局部变量分配默认值,只有实例变量。

        供参考,请看The docs

        默认值

        声明字段时并不总是需要赋值。 已声明但未初始化的字段将设置为 编译器合理的默认值。一般来说,这个默认值 将为零或空,具体取决于数据类型。依靠这样的 然而,默认值通常被认为是糟糕的编程 风格。

        下图总结了以上数据的默认值 类型。

        数据类型默认值(用于字段)
        字节 0
        短 0
        整数 0
        长0L
        浮动 0.0f
        double 0.0d
        char '\u0000'
        字符串(或任何对象) null
        布尔假

        局部变量略有不同;编译器从不分配 未初始化的局部变量的默认值。 如果您不能 在声明它的地方初始化你的局部变量,确保 在您尝试使用它之前为其分配一个值。访问一个 未初始化的局部变量将导致编译时错误。

        【讨论】:

          【解决方案5】:

          当你在一个方法中声明local variables时,你必须在使用它们之前给它们赋值。

          【讨论】:

            【解决方案6】:

            Java 编译器必须确信,当我们到达HERE 行时,它可以证明abc 已被设置为:

               boolean answerFound = false;
               int a, b, c;
               while (!answerFound) {
                   for (a = 1; a <= 1000; a++) {
                       for (b = a + 1; b <= 1000; b++) {
                           c = 1000 - a - b;
                           answerFound = determineIfPythagoreanTriple(a, b, c);
                       }
                   }
               }
               // HERE
            

            从编译器的角度来看,如果循环执行零次,那么它将到达HERE,而变量没有被初始化;因此,您不能使用它们。 我们知道这是不可能的,因为我们知道answerFound 被初始化为false,因此循环将至少执行一次,而且每个for 循环将在至少一次。但是语言必须有一致的规则来确定哪些程序是合法的,哪些是不合法的;为了避免事情过于复杂,编译器不需要进行证明abc 始终被初始化所需的推论。我没有详细查看实际的“确定分配”规则,但我认为它们已经相当复杂。

            因此,即使您知道变量将被初始化,您也无法让编译器相信这一点。因此,只需在声明它们时对其进行初始化。

            int a = 0, b = 0, c = 0;
            

            顺便说一句,由于while for 循环之外,所以当answerFound 变为true 时,此代码不会立即退出。它仍然执行for 循环直到它们完成,然后才测试是否离开while 循环。你需要解决这个问题。

            附:如果你想作弊,请注意每个毕达哥拉斯三元组的形式为 a = m2 - n2, b = 2mn,c = m2 + n2,对于一些mn时间>。实际上,您可以使用代数在没有计算机的情况下得到答案。但是继续完成你开始的程序——这是很好的练习。

            【讨论】:

              【解决方案7】:

              正如其他人指出的那样,您的变量 a, b, c 在您到达 System.out.println 时可能尚未初始化。有几种方法可以避免这种情况。

              显式地初始化变量,所以:

              int a = 0;
              

              使用 do...while 循环,确保您的循环至少运行一次,因此:

              do {
                  [...]
              } while (!answerFound);
              

              使用循环范围变量,避免局部范围的变量徘徊,所以:

              for (int a = 1; a <= 1000; a++) {
                  [...]
              }
              

              【讨论】:

                猜你喜欢
                • 2012-03-25
                • 2015-07-04
                • 1970-01-01
                • 2013-05-22
                相关资源
                最近更新 更多