前言
在java中final关键字可用于修饰类、变量和方法,用于表示它修饰的类、方法和变量都是不可变的。下面小编在剖析一下final关键字常用的场景。
Final成员变量
在java中成员变量是随类初始化或者对象初始化而初始化的,而对于final修饰的成员变量而言,一旦有了初始值,就不能被重新赋值,如果既没有在定义成员变量时指定初始值,也没有在初始化块、构造器中为成员变量指定初始值,那么将是系统默认分配的0、false或者null。总结一下为final修饰的成员变量也就以下两种情况:
类变量:必须在静态初始化块中指定初始值或者声明变量时指定初始值,而且只能在两个地方的其中之一指定。
实例变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方的其中之一指定。
看下面这个Demo,来了解一下各种情况。
package com.test;
public class FinalVariableTest {
// 定义成员变量时指定默认值,合法。
final int a = 6;
// 下面变量将在构造器或初始化块中分配初始值
final String str;
final int c;
final static double d;
// 既没有指定默认值,又没有在初始化块、构造器中指定初始值,
// 下面定义的ch实例变量是不合法的。
// final char ch;
// 初始化块,可对没有指定默认值的实例变量指定初始值
{
// 在初始化块中为实例变量指定初始值,合法
str = "Hello";
// 定义a实例变量时已经指定了默认值,
// 不能为a重新赋值,因此下面赋值语句非法
// a = 9;
}
// 静态初始化块,可对没有指定默认值的类变量指定初始值
static {
// 在静态初始化块中为类变量指定初始值,合法
d = 5.6;
}
// 构造器,可对既没有指定默认值、有没有在初始化块中
// 指定初始值的实例变量指定初始值
public FinalVariableTest() {
// 如果在初始化块中已经对str指定了初始化值,
// 构造器中不能对final变量重新赋值,下面赋值语句非法
// str = "java";
c = 5;
}
public void changeFinal() {
// 普通方法不能为final修饰的成员变量赋值
// d = 1.2;
// 不能在普通方法中为final成员变量指定初始值
// ch = 'a';
}
public static void main(String[] args) {
FinalVariableTest ft = new FinalVariableTest();
System.out.println(ft.a);
System.out.println(ft.c);
System.out.println(ft.d);
}
}
系统不会对局部变量进行初始化,局部变量必须由程序员进行初始化。如果final修饰的局部变量在定义时没有指定默认值,则可以在后面代码中指定,但是只能指定一次。
final方法
final修饰的方法不可以被重写,如果出于某些原因,不希望子类重写父类的方法,可以使用该关键字
final类
final修饰的类不可以有子类,因为如果有子类的话,那么子类可以访问到父类的某些方法,就可以来改写父类中的内部数据。
不可变类
不可以变类的意思是当创建该类实例后,该实例的实例变量是不可以修改的。那么如果要自定义不可变类的话,需要遵循以下规则
1.使用private和final修饰符类修饰该类的成员变量
2.提供带参数的构造器,用于根据传入的参数来初始化类里的成员变量
3.仅仅为该类的成员变量提供getter方法,不要为该类的成员变量提供setter方法,因为普通方法无法修改final修饰的成员变量