java反射中Filed的用法 java 反射 final_Java


Java经典语法系列

  1. Java面试宝典:final语义深度分析
  2. Volatile深度剖析-可见性
  3. Volatile深度剖析-原子性
  4. Volatile深度剖析-指令重排序
  5. Java经典语法糖:你真的理解泛型吗?

背景

在实际项目开发中,我们常常用final修饰的变量存储常量值,使得程序看起来优雅美观。

public static final String HIST_INDEX = "histpenddb";

更重要的是让我们放心安全的使用这个常量,不必担心常量值会变化。

基本语法

1、被final修饰的类不能被子类继承

final class FinalClass{}

final类不能被继承,所以没有子类。

在设计Java类时,如果这个类不需要有子类,其内部结构不允许被改变并且确信这个类以后不会被扩展修改,那么可以把这个类定义成final类。

2、被final修饰的方法不能被子类重写,但可以被继承

class FinalClass{ public final void finalTest(){}}

3、被final修饰的字段值不可修改

class FinalClass{ public static final boolean ENABLED = true; public final void finalTest(){} }

4、类中所有的私有方法(private)都隐式指定为final,因此私有方法默认是final类型的

5、final不能修饰构造方法

由第四条可知,构造方法变私有,就不能实例化对象。

内存语义

我们先了解下Java内存模型的重排序规则,这有利于我们理解final的内存语义。

重排序规则

Java为提高程序的执行性能,会对程序编码进行语义上的重排序。


java反射中Filed的用法 java 反射 final_java反射中Filed的用法_02

重排序流程


重排序规则分为三大类

  1. 编译级重排序
  2. 指令级重排序
  3. 内存级重排序

其中指令级重排序、内存级重排序属于处理器重排序

编译级重排序

不改变单线程程序语义前提下,重新安排指令的执行顺序

指令级重排序

指令并行技术可以将多条指令重叠执行,如果不存在数据依赖性,处理器会改变语句对应的机器指令执行顺序

内存屏障

为了防止一些重排序规则会改变程序计算结果,我们需要使用一些手段来禁止不必要重排序规则,称之为内存屏障。

就像我之前在《Volatile深度剖析-指令重排序》文章中举的栗子

白话来讲就是往你的一些代码里面动态插入一些屏障指令,目的是防止在多线程环境下,变量赋值错乱问题。这个就好比你家种的白菜,你是不是会担心白菜叶子会被鸡吃掉,那你会怎么做呢?想到什么了?对,用围栏把菜园子围起来,这样可以防止鸡偷吃白菜叶子。

内存屏障分类


java反射中Filed的用法 java 反射 final_java反射中Filed的用法_03


final内存语义

Java禁止final类型的写操作重排序到构造方法之外。

也就是说,类的成员变量必须在构造方法体初始化,当然final类型的成员变量也可以在定义时初始化。

另外,从编译器优化角度来说,会在final类型写入后,在构造方法返回之前插入内存屏障(StoreStore),以防止编译器重排序。

重排序规则和final内存语义可以看出,java设计final关键字的初衷:

在多线程环境下,为了实现类似于共享数据的需求,需把某些字段值变为常量,以便程序能够安全稳定的调用,不会因为字段值变化而导致程序执行错乱问题。