为什么必须在构造函数完成之前初始化最终变量?

时间:2012-07-05 13:12:14

标签: java

为什么必须在构造函数完成之前初始化最终变量?

public class Ex
{
  final int q;
}

当我编译这段代码时,我得到这样的错误

错误:变量q可能尚未初始化

9 个答案:

答案 0 :(得分:34)

官方原因是它由Java Language Specification 8.3.1.2定义:

  

必须在声明它的类的每个构造函数的末尾明确赋值空白的最终实例变量;否则会发生编译时错误。

空白决赛是一个最终变量,其声明缺少初始值(即你描述的内容)。

答案 1 :(得分:14)

因为final阻止你修改变量,但它必须在某个时候初始化,而构造函数是正确的位置。

在您的情况下,它将被称为blank final,因为它在声明时未初始化。

答案 2 :(得分:13)

final变量的值只能设置一次。构造函数是类的代码中唯一可以保证它将成立的地方;构造函数只能为一个对象调用一次,但其他方法可以被调用任意次。

答案 3 :(得分:10)

必须在声明或构造函数中初始化final变量。

如果构造函数返回时尚未初始化,则可能永远不会初始化,并且可能仍为未初始化的变量。编译器无法证明它将被初始化,因此会抛出错误。

Wikipedia excerpt解释得很好:

  

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

答案 4 :(得分:6)

应用于字段的final关键字具有两种效果之一:

  • 在基元上,它可以防止基元的值被更改(int不能改变值)
  • 在一个对象上,它可以防止“变量的值”,即对象的引用被改变。也就是说,如果你有一个final HashMap<String,String> a,你只能设置一次,而你将无法再次this.a=new HashMap<String,String>();但是没有什么能阻止你做this.a.put("a","b"),因为它不会修改引用,只会修改对象的内容。

答案 5 :(得分:2)

final修饰符会阻止您更改变量值,因此您必须在声明它的位置对其进行初始化。

答案 6 :(得分:0)

Final modifier不允许change your variable value。因此您需要在某个地方为其分配值,constructor是您在这种情况下必须执行此操作的位置。

答案 7 :(得分:0)

语言规范包含有关最终变量和字段属性的特定保证,其中之一是正确构造的对象(即构造函数成功完成的对象)必须将其所有最终实例字段初始化并对所有线程可见。因此,编译器会分析代码路径并要求您初始化这些字段。

答案 8 :(得分:0)

如果使用final关键字声明了实例变量,则意味着以后无法对其进行修改,这使其成为常量。这就是为什么我们必须使用final关键字初始化变量的原因。初始化必须明确进行,因为JVM不会为最终实例变量提供默认值。最终实例变量必须在声明时进行初始化,例如:

class Test{
   final int num = 10;
   }

或者必须在实例块中声明它,例如:

class Test{
 final int x;
  {
   x=10;
  }
} 

或 必须在构造函数COMPLETION之前声明它,例如:

class Test{
 final int x;
  Test(){ 
   x=10;
  }
}

请记住,我们可以在consructor块中对其进行初始化,因为初始化必须在构造函数完成之前完成。