final关键字

行文思路:

1 基本用法

2 final 关键字原理

3 与static关键字的区别

-----------------------------------------------------

1 基本用法:

a,final关键字修饰类。表明这个类不能被继承,一般来讲,除非这个类专门不让别人继承或者出于安全考虑,一般不要将类设置为final,此外,final修饰的类的成员方法会被隐式的制定为final 方法。

b,  final关键字修饰方法。可以防止任何继承类修改这个方法。

c,  final关键字修饰变量。基本数据类型或者String类型在编译的时候就能知道其确切值,一旦初始化之后就不能被改变。如果是引用类型,初始化之后是不能被改变指向另一个对像的,但是该内存地    

    址中保存的对象信息, 是可以进行修改的。

2 final 原理

对于final域,编译器和处理器要遵守两个重排序规则:

1.在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。

(先写入final变量,后调用该对象引用)

原因:编译器会在final域的写之后,插入一个StoreStore屏障

2.初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。

(先读对象的引用,后读final变量)

编译器会在读final域操作的前面插入一个LoadLoad屏障

第一种情况:写普通域的操作被编译器重排序到了构造函数之外

而写 final 域的操作,被写 final 域的重排序规则“限定”在了构造函数之内,读线程 B 正确的读取了 final 变量初始化之后的值。

写 final 域的重排序规则可以确保:在对象引用为任意线程可见之前,对象的 final 域已经被正确初始化过了,而普通域不具有这个保障。

第二种情况:读对象的普通域的操作被处理器重排序到读对象引用之前

而读 final 域的重排序规则会把读对象 final 域的操作“限定”在读对象引用之后,此时该 final 域已经被 A 线程初始化过了,这是一个正确的读取操作。

读 final 域的重排序规则可以确保:在读一个对象的 final 域之前,一定会先读包含这个 final 域的对象的引用。

如果 final 域是引用类型

对于引用类型,写 final 域的重排序规则对编译器和处理器增加了如下约束:

在构造函数内对一个 final 引用的对象的成员域的写入,与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。

3 与static关键字的区别

static 只是保存了一个副本,在初始化的时候被创建了,final 的作用是保障不可变,是两个东西。

原文地址:https://www.cnblogs.com/junbaba/p/14147742.html