为什么最终的实例变量不是默认值?

时间:2017-04-11 20:14:30

标签: java final

我正在准备Java OCA认证,在那里我遇到了类似的问题,如下所示:

public class TestClass {
    final int i;

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

根据Java,实例和静态变量都是默认值。令人惊讶的是,这是我的控制台中显示的错误:

error: variable i not initialized in the default constructor final int i;

为什么没有i分配上面的默认值?

6 个答案:

答案 0 :(得分:2)

final变量分配默认值会破坏首先使变量成为最终目的的全部目的。
final意味着您无法在分配后更改该值。 如果为最终变量赋予默认值,那么您将永远无法将变量的值设置为其他值(即使是第一次)。

答案 1 :(得分:2)

它是在Java Language Specification

中以这种方式定义的
  

第16章。明确分配

     

每个局部变量(§14.4)和每个空白final字段(§4.12.4§8.3.1.2)必须具有明确分配的值访问其价值。

     

[...]

     

对于本地变量或空白最终字段x的每次访问,必须在访问之前明确分配x,否则会发生编译时错误。

术语“空白final字段”指的是没有值或初始值设定项的最终字段,“明确分配”意味着无论如何都将分配字段:

  

明确赋值背后的想法是必须在访问的每个可能的执行路径上发生对局部变量或空final字段的赋值。同样,明确取消分配背后的想法是,在任何可能的赋值执行路径上,不允许对空白最终变量进行其他赋值。

除了通过规范抛出错误之外,决策背后还有逻辑推理。空白final字段的默认值没有意义。在您的情况下,空白final是一个整数,它只会被赋予0,您将无法更改它。变量的用途是什么?

另外,如果final变量未明确赋予默认值,为什么不首先初始化它?您之后无法重新分配,因为已经给出了默认值,为什么不立即初始化呢?

答案 2 :(得分:0)

标准整数默认为零,那么为0字面整数创建常量的重点是什么?它没有用处,因此您必须在初始化期间使用值创建一个常量。

答案 3 :(得分:0)

  

为什么在上述情况下没有指定默认值?任何人都可以   解释!

如果要提供默认值,那么您将无法更改其值。如果final关键字与变量一起使用,则意味着一旦分配了变量,就无法重新分配

Wikipedia:

  

最终变量只能通过一次初始化一次   初始化程序或赋值语句。它不需要   在声明点初始化:这称为"空白   最终"变量。类的空白最终实例变量必须是   肯定在它所在的类的每个构造函数中分配   声明;同样,一个空白的最终静态变量必须是明确的   在声明它的类的静态初始值设定项中赋值;   否则,在两种情况下都会发生编译时错误。 (注意:如果   变量是一个引用,这意味着变量不能   重新绑定引用另一个对象。但它的对象   如果引用最初是可变的,那么引用仍然是可变的。)

进一步阅读:

Definite Assignment

答案 4 :(得分:0)

错误消息具有误导性,因为它可以使用默认值初始化:

class FinalTest{
    final int x = printXAndInitializeIt();

    private int printXAndInitializeIt(){
        System.out.println("x before initialization = "+x);
        return 1;
    }

    public static void main(String[] args) {
        FinalTest ft = new FinalTest();
        System.out.println("x after initialization = "+ft.x);
    }
}

输出:

x before initialization = 0
x after initialization = 1

但即使有默认值final变量需要显式初始化,因为在大多数情况下,缺少初始化是由错误引起的。这个错误可能会改为警告,但我猜Java设计师虽然“比安全感更好”。

答案 5 :(得分:0)

并不是最终字段没有被初始化为默认值 - 实际上它们是 ,但是你只会观察到这样的事实,如果你&# 39;重做一些愚蠢的事情 - 但是你需要明确地初始化它们一次(作为声明的一部分,或者在初始化程序块中,或者在每个构造函数中)。

要了解此动机,请考虑以下代码:

public class Foo {
    private final int mValue;

    public Foo(final boolean shouldSet) {
        if (shouldSet) {
            mValue = 1;
        }
    }

    // ...
}

如果该字段不是最终字段,则编译器会在其声明结尾处推断出隐式= 0;但最后一个字段并不总是有效。 。 。在上面的例子中,编译器甚至不能事先告诉它是否有效。因此,编译器通过从不推断隐式= 0来回避问题,并要求显式初始化。