成员变量是随类初始化或对象初始化而初始化的,当类初始化时,系统会为该类的类变量分配内存,并分配默认值;当创建对象时,系统会为该对象的实例变量分配内存,并分配默认值。也就是说,当执行静态初始化块时可以对类变量赋初始值,当执行普通初始化块、构造器时可以对实例变量赋初始值。
对final修饰的成员变量而言,一旦有了初始值,就不能被重新赋值,如果既没有在定义成员变量时指定初始值,也没有在初始化块、构造器中为成员变量指定初始值,那么这些成员变量的值将一直是系统默认分配的0、’\u0000’、false或null,这些成员变量也就完全失去了存在的意义。因此Java语法规定:final修饰的成员变量必须由程序猿显式地指定初始值。
归纳起来,final修饰的类变量、实例变量能指定初始值的地方如下。
- 类变量:必须在静态初始化块中指定初始值或者声明该类变量时指定初始值,而且只能在两个地方的其中之一。
- 实例变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方的其中之一指定。
final修饰的实例变量,要么在定义该实例变量时指定初始值,要么在普通初始化块或构造器中为该实例变量指定初始值。但需要注意的是,如果普通初始化块已经在为某个实例变量指定了初始值,则不能再在构造器中为该实例变量指定初始值;final修饰的类变量,要么定义该类变量时指定初始值,要么在静态初始化块中为该类变量指定初始值。
实例变量不能在静态初始化中指定初始值,因为静态初始化块时静态成员,不可访问实例变量–非静态成员;类变量不能在普通初始化块中指定初始值,因为类变量在类初始化阶段已经被初始化了,普通初始化块不能对其重新赋值。