基本介绍
final 可以修饰类、属性、方法和局部变量。在某些情况下,会使用到 final。
- 当不希望类被继承时,可以用 final 修饰【final class 类名】
- 当不希望父类的某个方法被子类覆盖(重写)时,可以用 final 关键字修饰 【访问修饰符 final 返回类型 方法名(){}】
- 当不希望类的某个属性的值被修改,可以用 final 修饰【访问修饰符 final 数据类型 数据名】
- 当不希望某个局部变量被修改,可以使用 final 修饰【final 数据类型 数据名】
使用细节
- final 修饰的属性又叫常量,一般用大写字母和下划线命名
- final 修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在以下三个位置之一:
- 在定义时
- 在构造器中
- 在普通代码块中
class A {
// 1、在定义时赋初值
private final int NUM1 = 1;
private final int NUM2;
private final int NUM3;
// private final int NUM4;
public A() {
// 2、在构造器中赋初值
NUM2 = 2;
}
{ // 在普通代码块中赋初值
NUM3 = 3;
}
static {
// NUM4 = 4; // 报错
}
}
- 如果 final 修饰的属性是静态的,则初始化的位置只能是以下两个位置:
- 定义时
- 在静态代码块中(不能在构造器中赋值,因为静态代码比构造器先执行)
class B {
// 1、在定义时赋初值
private static final int NUM1 = 1;
// private static final int NUM2;
private static final int NUM3;
// private static final int NUM4;
public B() {
// 因为可能在没有创建对象时就使用静态变量,此时被 final 修饰的静态变量没有被初始化
// 因此不允许在构造器中赋初值,因为会被认为没有对 final 修饰的变量进行初始化
// NUM2 = 2; // 报错
}
static { // 在静态代码块中赋初值
NUM3 = 3;
}
{
// NUM4 = 4; // 报错
}
}
- final 类不能继承,但是可以实例化对象
- 如果类不是 final 类,但是含有 final 方法,则该方法虽然不能重写,但是可以被继承,即子类继承父类之后,可以使用父类里被 final 修饰的方法,可以使用但是不可以重写
- 一般来说,如果一个类是 final 类,就没有必要再用 final 修饰类中的方法了,因为已经是 final 类了,也就不会被继承,不存在子类,也就不存在重写的情况
- final 不能修饰构造器
- final 和 static 往往搭配使用效率更高,不会导致类加载,因为底层编译器做了优化处理
public class Test {
public static void main(String[] args) {
/*
* 当 num 只用 static 修饰时,访问 num 会导致类加载
* 输出:
* 静态代码块被调用...
* 100
* 当 num 同时用 static 和 final 修饰时,访问 num 不会导致类加载
* 输出:
* 100
*/
System.out.println(C.num);
}
}
class C {
// 会导致类加载
// public static int num = 100;
// 不会导致类加载
public final static int num = 100;
static {
System.out.println("静态代码块被调用...");
}
}
- 包装类(Integer、Double、Float 等)和 String 都是 final 类,都是不能被继承的