final这个关键字, 其实在多种语言中都有出现, 对普通人而言, 我们使用它的频率肯定是不多的, 常见场景就是把它当C/C++中的
const来定义常量, 那么通过阅读不少源码后, 会发现它的出场频率极其的高,有必要全面的认真学习一下它.PS:关于源码中函数式编程的内容参考之前一篇 ,后续衍变为源码阅读系列 ?
0x00.简介
简单的定义:
final的作用是–使其修饰的变量是不可改变的, 使用它目的是改善**”设计“** 和**”效率“, 也就是说当你看到使用final的地方, 不知道为什么用, 就从这两个方面去想, 效率简单可以理解为C/C++中的宏**和常量.其实
final在不同的场景下, 语义是相差甚多的,想深入理解final, 必须全面的对它探究一番
final可以修饰OOP中大部分元素. 大体分为4类:
- Variable/Field (变量/域)
- Method (方法)
- Class (类)
- Method params (方法的形参,特别)
final修饰时位于static后, 类型前, 比如public static final float num = 0.1f; 用于修饰变量的时候是最好理解的, 效果类似于const(常量) ,但是补充说一句,其实const在java中也是作为一个保留字 存在的,只不过基本不会使用. 那么大家关注的核心显然是再后面修饰方法和修饰类上 .
0x01.从表面看final
表面看它其实很容易被滥用, 因为大部分人写代码不会考虑很好的向下兼容和后续重写, 所以工程上说, 除了跟宏一样过度使用会导致打破平衡点, 我觉得还是推荐默认使用的.
也就是说, 如果你不知道这个类/方法/对象是否需要改变/继承/重写, 可以都当默认成**不需要 , 这也是为什么源码里面的确会超大量**的使用final, 并不是说那个地方非得final ,而是形成了习惯, 就像C/C++中宏也会被滥用, 但是各种库,甚至内核里照样到处都是…
0x02.从编译器看final
有点懒得写… 因为内联其实很像宏, 宏我觉得挺好理解了, 再从JVM角度去磕意义不大, 有兴趣的可以自己反编译看看字节码.
0x03.综合来看final
先来个简单总结吧, 其实看完final发现其实不管是从什么角度, 编译器, 类加载器或者是设计模式上, 都是很难简单说清楚它的精准用法的. 效率起见, 先说一下大部分时候它四个修饰场景的意义:
- 修饰
class的时候, 此时这个类不能被任何类继承. 默认class中所有方法也都是final的, 所有方法类似于C中的宏化, 大部分时候调用效率会提高. - 单独修饰方法. 除了避免被重写(实际也很少见), 也就是
宏化提高效率 - 修饰基本类型基本等同于常量, 编译器可以更快读取. 修饰对象类型, 本质使其
引用固定? 意义? - 修饰形参(方法中的), 用处? (这个说实话我还没很认真看hh, 后续补一下)
更新: 后面觉得写的太浅就先不添加后续了, 理解原理还是得从 C/OS/ASM 角度来看问题, 上层 java 的确封装太重了