背景
在函数式编程学习中,学习闭包的时候,认识到了一个新词 effective final 之前没有了解过,于是查找,做下记录,具体内容如下
查询结果
在Java中,final 和 effective final 是两个相关但不同的概念,它们都与变量的不可变性有关,但适用的场景和含义有所不同。
final 关键字
final 是一个关键字,可以应用于类、方法和变量(包括实例变量、静态变量和局部变量)。对于不同类型的元素,final 的作用也有所不同:
- 类:当一个类被声明为
final时,它不能被继承。这意味着你不能创建该类的子类。 - 方法:当一个方法被声明为
final时,它不能被子类重写。这可以用于防止子类改变父类的方法行为。 - 变量:当一个变量被声明为
final时,它的值一旦被初始化就不能再被修改。对于基本数据类型,这意味着它的值是固定的;对于对象引用,这意味着引用本身不能指向另一个对象,但是对象内部的状态是可以改变的(除非该对象自身是不可变的)。
final int x = 10; // 基本数据类型
x = 20; // 错误: 不能重新赋值
final StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // 正确: 对象状态可以改变
sb = new StringBuilder("Goodbye"); // 错误: 不能重新赋值引用
effective final
effective final 并不是一个关键字,也不是Java语言的正式术语,而是指一种编程实践或特性。一个变量被称为 effective final,如果它虽然没有被显式地声明为 final,但在它的整个生命周期中只被初始化一次,并且之后不再被修改。这样的变量在功能上等同于 final 变量。
重要应用场景
- Lambda表达式:从Java 8开始,Lambda表达式只能访问局部变量或方法参数,如果这些变量或参数是
final或者effective final。这是因为Lambda表达式可能会在不同的线程中执行,而Java需要确保这些变量不会在Lambda表达式的生命周期内发生变化,以避免并发问题。
public class LambdaExample {
public static void main(String[] args) {
int num = 1; // effective final
Runnable r = () -> System.out.println(num); // 正确: 使用了 effective final 变量
num = 2; // 如果在此处修改 num,则会编译错误
r.run();
}
}
- 匿名内部类:类似地,在匿名内部类中,你只能引用那些是
final或effective final的局部变量和方法参数。
public class AnonymousInnerClassExample {
public static void main(String[] args) {
int value = 42; // effective final
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(value); // 正确: 使用了 effective final 变量
}
}).start();
// value = 43; // 如果在此处修改 value,则会编译错误
}
}
总结
final是一个明确的修饰符,用来声明类、方法或变量为不可变的。effective final是指那些实际上未被重新赋值的局部变量或方法参数,即使它们没有被显式地声明为final。这种特性使得它们可以在Lambda表达式和匿名内部类中安全使用。
理解这两者的区别有助于编写更清晰、更安全的代码,尤其是在使用Lambda表达式和匿名内部类时。