Appearance
12.2 final 关键字
final 关键字的概念
final 是 Java 中的一个关键字,用于修饰类、方法和变量。被 final 修饰的成员具有不可变性。
final 关键字的用途
1. final 类
被 final 修饰的类不能被继承。
语法:
java
final class 类名 {
// 类体
}示例:
java
// final 类,不能被继承
final class FinalClass {
public void display() {
System.out.println("This is a final class");
}
}
// 错误:不能继承 final 类
// class SubClass extends FinalClass {
// }
public class FinalClassExample {
public static void main(String[] args) {
FinalClass finalClass = new FinalClass();
finalClass.display();
}
}2. final 方法
被 final 修饰的方法不能被重写。
语法:
java
[访问修饰符] final 返回类型 方法名([参数列表]) {
// 方法体
}示例:
java
class ParentClass {
// final 方法,不能被重写
public final void finalMethod() {
System.out.println("This is a final method in ParentClass");
}
// 普通方法,可以被重写
public void nonFinalMethod() {
System.out.println("This is a non-final method in ParentClass");
}
}
class ChildClass extends ParentClass {
// 错误:不能重写 final 方法
// public void finalMethod() {
// System.out.println("Trying to override final method");
// }
// 正确:可以重写普通方法
@Override
public void nonFinalMethod() {
System.out.println("Overriding non-final method in ChildClass");
}
}
public class FinalMethodExample {
public static void main(String[] args) {
ChildClass child = new ChildClass();
child.finalMethod(); // 调用父类的 final 方法
child.nonFinalMethod(); // 调用子类重写的方法
}
}3. final 变量
被 final 修饰的变量一旦初始化后就不能再修改。
语法:
java
[访问修饰符] final 数据类型 变量名 [= 初始值];示例:
java
public class FinalVariableExample {
// final 成员变量,必须在声明时或构造方法中初始化
private final int finalMemberVar = 100;
private final String finalMemberStr;
// 构造方法中初始化 final 成员变量
public FinalVariableExample() {
finalMemberStr = "Hello, final!";
}
public void method() {
// final 局部变量,一旦初始化就不能修改
final int finalLocalVar = 200;
System.out.println("finalLocalVar: " + finalLocalVar);
// 错误:不能修改 final 局部变量
// finalLocalVar = 300;
// 错误:不能修改 final 成员变量
// finalMemberVar = 400;
// finalMemberStr = "New value";
}
public static void main(String[] args) {
FinalVariableExample example = new FinalVariableExample();
System.out.println("finalMemberVar: " + example.finalMemberVar);
System.out.println("finalMemberStr: " + example.finalMemberStr);
example.method();
}
}4. final 与基本数据类型
对于基本数据类型,final 修饰的是值,一旦赋值就不能修改。
示例:
java
public class FinalPrimitiveExample {
public static void main(String[] args) {
// final 基本数据类型变量
final int age = 18;
final double pi = 3.14159;
final char grade = 'A';
final boolean isTrue = true;
System.out.println("age: " + age);
System.out.println("pi: " + pi);
System.out.println("grade: " + grade);
System.out.println("isTrue: " + isTrue);
// 错误:不能修改 final 基本数据类型变量
// age = 19;
// pi = 3.14;
// grade = 'B';
// isTrue = false;
}
}5. final 与引用数据类型
对于引用数据类型,final 修饰的是引用,一旦指向某个对象,就不能再指向其他对象,但对象本身的内容可以修改。
示例:
java
public class FinalReferenceExample {
public static void main(String[] args) {
// final 引用数据类型变量
final int[] numbers = {1, 2, 3, 4, 5};
final StringBuilder sb = new StringBuilder("Hello");
System.out.println("numbers[0]: " + numbers[0]);
System.out.println("sb: " + sb);
// 正确:可以修改对象的内容
numbers[0] = 100;
sb.append(", Java!");
System.out.println("numbers[0] after modification: " + numbers[0]);
System.out.println("sb after modification: " + sb);
// 错误:不能修改引用指向的对象
// numbers = new int[]{6, 7, 8, 9, 10};
// sb = new StringBuilder("Hi");
}
}final 关键字的特点
- 不可继承:
final类不能被继承 - 不可重写:
final方法不能被重写 - 不可修改:
final变量一旦初始化就不能修改 - 必须初始化:
final成员变量必须在声明时或构造方法中初始化 - 提高安全性:防止子类修改父类的关键方法或变量
- 提高性能:编译器可能会对
final变量进行优化
示例:final 关键字的应用
示例 1:常量定义
java
public class Constants {
// 常量定义
public static final double PI = 3.14159265358979323846;
public static final int MAX_AGE = 150;
public static final int MIN_AGE = 0;
public static final String DEFAULT_NAME = "Unknown";
public static final int[] MONTHS = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 私有构造方法,防止创建对象
private Constants() {
}
}
public class ConstantsExample {
public static void main(String[] args) {
System.out.println("PI: " + Constants.PI);
System.out.println("MAX_AGE: " + Constants.MAX_AGE);
System.out.println("MIN_AGE: " + Constants.MIN_AGE);
System.out.println("DEFAULT_NAME: " + Constants.DEFAULT_NAME);
System.out.println("Days in January: " + Constants.MONTHS[0]);
}
}示例 2:防止方法重写
java
class Shape {
// final 方法,确保所有子类都使用相同的计算面积的方法
public final double calculateArea(double radius) {
return Math.PI * radius * radius;
}
// 普通方法,子类可以重写
public void draw() {
System.out.println("Drawing a shape");
}
}
class Circle extends Shape {
// 正确:可以重写 draw 方法
@Override
public void draw() {
System.out.println("Drawing a circle");
}
// 错误:不能重写 calculateArea 方法
// @Override
// public double calculateArea(double radius) {
// return 0;
// }
}
public class FinalMethodApplication {
public static void main(String[] args) {
Circle circle = new Circle();
circle.draw();
double area = circle.calculateArea(5);
System.out.println("Circle area: " + area);
}
}示例 3:不可变类
java
// 不可变类,所有属性都是 final 的
final class ImmutablePerson {
private final String name;
private final int age;
private final String address;
public ImmutablePerson(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getAddress() {
return address;
}
// 没有 setter 方法,确保属性不能被修改
}
public class ImmutableExample {
public static void main(String[] args) {
ImmutablePerson person = new ImmutablePerson("John", 30, "New York");
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
System.out.println("Address: " + person.getAddress());
// 无法修改属性,因为没有 setter 方法,且属性是 final 的
}
}常见问题
1. final 成员变量未初始化
症状:编译错误:Variable 'variableName' might not have been initialized
解决方案:确保 final 成员变量在声明时或构造方法中初始化
示例:
java
public class FinalInitializationExample {
// 错误:final 成员变量未初始化
// private final int value;
// 正确:在声明时初始化
private final int value1 = 100;
// 正确:在构造方法中初始化
private final int value2;
public FinalInitializationExample() {
value2 = 200;
}
// 正确:在构造方法中初始化
private final int value3;
public FinalInitializationExample(int value3) {
this.value3 = value3;
}
}2. 尝试修改 final 变量
症状:编译错误:Cannot assign a value to final variable 'variableName'
解决方案:不要尝试修改 final 变量的值
示例:
java
public class ModifyFinalExample {
public static void main(String[] args) {
final int value = 100;
// 错误:不能修改 final 变量
// value = 200;
System.out.println("value: " + value);
}
}3. 尝试继承 final 类
症状:编译错误:Cannot inherit from final 'FinalClass'
解决方案:不要尝试继承 final 类
示例:
java
final class FinalClass {
}
// 错误:不能继承 final 类
// class SubClass extends FinalClass {
// }4. 尝试重写 final 方法
症状:编译错误:Cannot override the final method from ParentClass
解决方案:不要尝试重写 final 方法
示例:
java
class ParentClass {
public final void finalMethod() {
}
}
class ChildClass extends ParentClass {
// 错误:不能重写 final 方法
// @Override
// public void finalMethod() {
// }
}最佳实践
常量使用 final:使用
final定义常量,特别是与static一起使用关键方法使用 final:对于不希望被子类重写的方法,使用
final修饰不可变类使用 final:对于需要不可变的类,使用
final修饰类和所有属性局部变量使用 final:对于方法中不需要修改的局部变量,使用
final修饰,提高代码可读性避免过度使用 final:只在需要时使用
final,不要滥用
总结
final 关键字是 Java 中的一个重要关键字,用于修饰类、方法和变量。被 final 修饰的成员具有不可变性。
final 关键字的主要用途:
final类:不能被继承final方法:不能被重写final变量:一旦初始化就不能修改
final 关键字的特点:
- 不可继承:
final类不能被继承 - 不可重写:
final方法不能被重写 - 不可修改:
final变量一旦初始化就不能修改 - 必须初始化:
final成员变量必须在声明时或构造方法中初始化 - 提高安全性:防止子类修改父类的关键方法或变量
- 提高性能:编译器可能会对
final变量进行优化
通过合理使用 final 关键字,可以提高代码的安全性、可维护性和性能。
