目录
1. final关键字的语义
-
final修饰基本数据类型变量时,该变量的值在初始化后就不可改变了;
-
final修饰引用类型变量时,该变量在初始化后不能再执行赋值操作,也就是改变量指向的内存地址不能再改变,但是该变量所指向的内存中的数据是可以被改变的。
2. 如何保证final的语义
final关键字保证被修饰的变量在任何时候呈现出来的值都是一致的(在构造函数中正确初始化过的),为了做到这一点,JMM必须对编译器和处理器的重排序进行限制:
- 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。该规则包括两个部分:
- JMM禁止编译器将final域的写入重排序到构造器函数之外
- 编译器在final域的写入之后,构造函数return之前加入一个StoreStore屏障,这个屏障禁止处理器把final域的写重排序到构造函数之外。
- 初次读一个含有final域的对象的引用,与随后初次读这个对象的final域,这两个操作不能重排序。事实上,这两个操作是具有间接依赖关系的,所以编译器一定不会将这两个操作进行重排序。大多数处理器也会遵守间接依赖关系,不会重排序这两个操作,但是也有少数处理器允许具有间接依赖关系的操作重排序,所以该规则只针对处理器。具体实现是,编译器会在读final域的前面插入一个LoadLoad屏障。
- 当final域是引用类型时,写final域的重排序规则对编译器和处理器增加了如下规则:在构造函数内对一个final引用的对象的成员域的写入,与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。