Skip to content

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 关键字的特点

  1. 不可继承final 类不能被继承
  2. 不可重写final 方法不能被重写
  3. 不可修改final 变量一旦初始化就不能修改
  4. 必须初始化final 成员变量必须在声明时或构造方法中初始化
  5. 提高安全性:防止子类修改父类的关键方法或变量
  6. 提高性能:编译器可能会对 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() {
    // }
}

最佳实践

  1. 常量使用 final:使用 final 定义常量,特别是与 static 一起使用

  2. 关键方法使用 final:对于不希望被子类重写的方法,使用 final 修饰

  3. 不可变类使用 final:对于需要不可变的类,使用 final 修饰类和所有属性

  4. 局部变量使用 final:对于方法中不需要修改的局部变量,使用 final 修饰,提高代码可读性

  5. 避免过度使用 final:只在需要时使用 final,不要滥用

总结

final 关键字是 Java 中的一个重要关键字,用于修饰类、方法和变量。被 final 修饰的成员具有不可变性。

final 关键字的主要用途:

  • final 类:不能被继承
  • final 方法:不能被重写
  • final 变量:一旦初始化就不能修改

final 关键字的特点:

  • 不可继承:final 类不能被继承
  • 不可重写:final 方法不能被重写
  • 不可修改:final 变量一旦初始化就不能修改
  • 必须初始化:final 成员变量必须在声明时或构造方法中初始化
  • 提高安全性:防止子类修改父类的关键方法或变量
  • 提高性能:编译器可能会对 final 变量进行优化

通过合理使用 final 关键字,可以提高代码的安全性、可维护性和性能。

© 2026 编程马·菜鸟教程 版权所有