Java 中 final 与 effectively final

Java 中 final 与 effectively final

一、为什么我们需要 finaleffectively final

为什么这些关键字重要?

在 Java 中,一些变量需要在初始化后不再变化,以确保程序的安全性和可读性。

为什么你需要关心 finaleffectively final

  1. 防止变量进一步修改导致的不可控度问题。
  2. 提高代码可读性和维护性。
  3. 对于区别 finaleffectively final 来说,懂得它们之间的区别,你就能更好地利用 lambda 表达式和匿名内部类。

二、final 关键字

定义:
finalJava 的编译时常量修饰符,可用于变量、方法和类,表示在初始化后不能被修改。

基本规则:

  • 必须在 声明时或初始化块中 显式赋值。
  • 无法再次赋值或修改。

示例:

// 1. 变量声明时初始化
final int MAX_VALUE = 100;

// 2. 初始化块中赋值
class MyClass {
    final String name;
    {
        name = "Test"; // 这里允许赋值
    }
}

使用场景:

  • 常量值(例如数学常量 PI
  • 确保方法参数不可改
  • 防止类被继承 (final class MyClass)
  • 防止方法被重写 (final void myMethod())

限制:

final int x = 10;
x = 20; // 编译错误:无法为最终变量 x 赋值

三、effectively final

定义:
Java 8 引入了 effectively final 概念,用于区分部分已经在初始化后不再被修改的局部变量,尽管未显式使用 final

基本规则:

  • 只适用于局部变量(不包括类字段)
  • 如果初始化后不再修改,则被自动视为 final

示例:

int effectivelyFinalVar = 10;

Runnable runnable = () -> {
    System.out.println(effectivelyFinalVar); // 允许访问
};

使用场景:

  • Lambda 表达式和匿名内部类
  • 优化代码,避免不必要的 final 修饰符

限制:

int count = 0;
Runnable counter = () -> {
    count++; // 编译错误:该变量不是 effectively final
};
public void test() {
    int x = 10; // 初始化
    x = 5;     // 重新赋值,破坏 effectively final
    Runnable r = () -> System.out.println(x); // 编译错误
}
public void testEffectivelyFinal() {
    String effectivelyFinalStr = "Hello";
    // 以下代码编译错误
    // effectivelyFinalStr = "World";

    Runnable efLambda = () -> {
        System.out.println(effectivelyFinalStr); // 允许访问
    };
}

四、final vs effectively final 比较

特性 final effectively final
修饰符显式性 必须显式声明 隐式规则 (编译器自动推断)
适用范围 类字段、方法、类、局部变量 仅适用于局部变量

你可能感兴趣的:(【原来如此】,java,开发语言)