Java final关键字

01、final变量

被 final 修饰的变量无法重新赋值。换句话说,final 变量一旦初始化,就无法更改。

看这行代码

final int age = 18;

当尝试将 age 的值修改为 30 的时候,编译器就报错了。

image-20250723175915524

再看如下代码

public class Pig {
   private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

这是一个很普通的 Java 类,它有一个字段 name。然后,我们创建一个测试类,并声明一个 final 修饰的 Pig 对象。

final Pig pig = new Pig();

如果尝试将 pig 重新赋值的话,编译器同样会报错。

image-20250723184548554

但我们仍然可以去修改 pig 对象的 name。

final Pig pig = new Pig();
pig.setName("特立独行");
System.out.println(pig.getName()); // 特立独行

final 和 static 一起修饰的成员变量叫做常量,常量名必须全部大写。

public class Pig {
   private final int age = 1;
   public static final double PRICE = 36.5;
}

有时候,我们还会用 final 关键字来修饰参数,它意味着参数在方法体内不能被再修改。

public class ArgFinalTest {
    public void arg(final int age) {
    }

    public void arg1(final String name) {
    }
}

如果尝试去修改它的话,编译器会提示以下错误。

image-20250723184814983

02、final方法

被 final 修饰的方法不能被重写。如果我们在设计一个类的时候,认为某些方法不应该被重写,就应该把它设计成 final 的。

Thread 类就是一个例子,它本身不是 final 的,这意味着我们可以扩展它,但它的 isAlive() 方法是 final 的。

public class Thread implements Runnable {
    public final native boolean isAlive();
}

需要注意的是,该方法是一个本地(native)方法,用于确认线程是否处于活跃状态。而本地方法是由操作系统决定的,因此重写该方法并不容易实现。

来看这段代码。

public class Actor {
    public final void show() {

    }
}

当我们想要重写该方法的话,就会出现编译错误。

image-20250723185128829

思考一下:一个类是 final 的,和一个类不是 final,但它所有的方法都是 final 的,考虑一下,它们之间有什么区别?

我能想到的一点,就是前者不能被继承,也就是说方法无法被重写;后者呢,可以被继承,然后追加一些非 final 的方法。

03、final类

如果一个类使用了 final 关键字修饰,那么它就无法被继承…

String 类就是一个 final 类。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence,
               Constable, ConstantDesc {}

你知道为什么 String 类要设计成 final 吗?

原因大致有 3 个:

  • 为了实现字符串常量池
  • 为了线程安全
  • 为了 HashCode 的不可变性

任何尝试从 final 类继承的行为将会引发编译错误。来看这段代码。

public final class Writer {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

尝试去继承它,编译器会提示以下错误,Writer 类是 final 的,无法继承。

image-20250723185458381

不过,类是 final 的,并不意味着该类的对象是不可变的。

Writer writer = new Writer();
writer.setName("Hanserwei");
System.out.println(writer.getName()); // Hanserwei

Writer 的 name 字段的默认值是 null,但可以通过 settter 方法将其更改为Hanserwei。也就是说,如果一个类只是 final 的,那么它并不是不可变的全部条件。

把一个类设计成 final 的,有其安全方面的考虑,但不应该故意为之,因为把一个类定义成 final 的,意味着它没办法继承,假如这个类的一些方法存在一些问题的话,我们就无法通过重写的方式去修复它。