final 关键字
本课属于 Coddy Java 学习旅程的“面向对象编程”单元。第 13 课,共 87 课。
Java 中的 final 关键字可以防止修改。它可用于变量、方法和类,并分别产生不同的效果。
将 final 用于变量时,它会使变量成为常量。赋值后,它的值就不能更改:
public class Circle {
private final double PI = 3.14159;
private final double radius;
public Circle(double radius) {
this.radius = radius; // 可以在构造函数中赋值一次
}
public void setRadius(double r) {
// this.radius = r; // 错误!不能给 final 变量重新赋值
}
}一个 final 变量必须在声明时或构造函数中初始化。之后,任何重新赋值的尝试都会导致编译错误。
对于引用类型,final表示引用不能指向其他对象,但对象的内容仍然可以改变:
private final StringBuilder name = new StringBuilder("John");
// name = new StringBuilder("Jane"); // 错误!不能重新赋值
name.append(" Doe"); // 没问题!对象的内容可以改变对字段使用 final 可以清楚地表达意图,告诉其他开发者,这个值在初始化后不应再改变。这对于配置值、ID 或任何必须在对象的整个生命周期内保持不变的数据尤其有用。
final 方法不能在子类中被重写:
class Base {
public final void greet() {
System.out.println("Hi");
}
}
class Child extends Base {
// public void greet() { } // 错误!Base 中的 greet() 是 final 方法
}final 类完全不能被扩展。String 是一个 final 类,因此没有任何类可以扩展它:
final class Config { }
// class MyConfig extends Config { } // 错误!Config 是 final 类挑战
简单我们来构建一个 Student 注册系统,使用 final 关键字保护学生注册后不应更改的数据。
你将创建两个文件来组织代码:
Student.java:创建一个 Student 类,其中某些信息设置后将永久锁定:- 一个
final字段studentId(String),创建时赋值,之后永远不能更改 - 一个
final字段enrollmentYear(int),表示学生入学的年份,也会永久保留 - 一个普通的私有字段
name(String),如果学生更改姓名,可以更新此字段 - 一个接收全部三个值并初始化字段的构造函数
- 一个用于获取学生 ID 的 getter
getStudentId() - 一个用于获取入学年份的 getter
getEnrollmentYear() - 一个用于获取姓名的 getter
getName()和一个用于设置姓名的 settersetName() - 一个返回以下内容的方法
getInfo():"ID: [studentId] | Name: [name] | Enrolled: [enrollmentYear]"
- 一个
Main.java:创建一个 Student 对象,然后更新其姓名并显示其信息。你将收到 4 个输入:学生 ID、初始姓名、入学年份,以及要更新成的新姓名。打印两行:- 姓名更改前的学生信息
- 姓名更改后的学生信息
你将依次收到 4 个输入:studentId(String)、name(String)、enrollmentYear(int)和 newName(String)。
注意,final 字段会保护学生的 ID 和入学年份,这些都是不应更改的永久记录;姓名则可以通过 setter 更新。
亲手试试
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取输入
String studentId = scanner.nextLine();
String name = scanner.nextLine();
int enrollmentYear = scanner.nextInt();
scanner.nextLine(); // 读取换行符
String newName = scanner.nextLine();
// TODO: 用初始值创建一个 Student 对象
// TODO: 在更改姓名前输出学生信息
// TODO: 使用 setter 更新学生的姓名
// TODO: 在更改姓名后输出学生信息
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Java 在线编译器