谈谈 final
2020-04-16 本文已影响0人
巴巴11
1 lambda访问外部变量必须是final的。
lambda本质是一个匿名内部类。
匿名内部类无法访问外部类方法的局部变量(每个方法都有自己的栈帧,匿名内部类的执行和外部方法可能不在一个线程里,当访问局部变量时,可能该变量已经被回收了,final类型的局部变量在lambda匿名类里其实是局部变量的一个拷贝)。
局部变量是存储在栈上的,而栈上的内容在当前线程执行完成之后就会被GC回收掉。
lambda表达式最终被处理为一个额外的线程去执行。绝对不是上面提到的线程。如果上面的线程执行完了,而这个线程又使用到了上面提到的局部变量会出现错误。
外部类的局部变量,只能通过匿名内部类的构造方法传进去。
lambda是拥抱函数式编程,而函数式编程本身不应该为函数引入状态,final修饰的变量不可修改也是迎合了这一点。
2. final修饰变量,类,方法
- 被final修饰的类不可以被继承
- 被final修饰的方法不可以被重写
- 被final修饰的变量不可变(被final修饰的变量,不可变的是变量的引用,而不是变量的内容)
- 被final修饰的常量,在编译阶段会存入调用类的常量池中
final修饰基本类型变量
当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变
final修饰引用类型变量
当使用final修饰引用类型变量时,它保存的仅仅是一个引用,final只能保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以改变
package com.mxixm.spring.mvc;
import java.util.Arrays;
public class Main1 {
public static void main(String[] args) {
/**
* final修饰基本类型变量
* 当使用final修饰基本类型变量时,
* 不能对基本类型变量重新赋值,因此基本类型变量不能被改变
*/
final int i = 1;
// i = 2; // no....
/**
* final修饰引用类型变量
* 当使用final修饰引用类型变量时,
* 它保存的仅仅是一个引用,
* final只能保证这个引用类型变量所引用的地址不会改变,
* 即一直引用同一个对象,但这个对象完全可以改变
*/
final int[] arr = new int[]{1, 2};
System.out.println(Arrays.toString(arr));
Arrays.sort(arr); //
System.out.println(Arrays.toString(arr));
// arr = null; // no....
arr[0] = 10; // yes...
final InnerCls cls = new InnerCls();
cls.name = "test"; // yes...
// cls == new InnerCls(); // no....
}
static class InnerCls {
String name;
}
}