1. final的简介
final可以修饰变量,方法和类,用于表示所修饰的内容一旦赋值之后就不会再被改变,比如String类就是一个final类型的类。即使能够知道final具体的使用方法,我想对final在多线程中存在的重排序问题也很容易忽略,希望能够一起做下探讨。
2. final的具体使用场景
final能够修饰变量,方法和类,也就是final使用范围基本涵盖了java每个地方,下面就分别以锁修饰的位置:变量,方法和类分别来说一说。
2.1 变量
在java中变量,可以分为成员变量以及方法局部变量。因此也是按照这种方式依次来说,以避免漏掉任何一个死角。
2.1.1 final成员变量
通常每个类中的成员变量可以分为类变量(static修饰的变量)以及实例变量。针对这两种类型的变量赋初值的时机是不同的,类变量可以在声明变量的时候直接赋初值或者在静态代码块中给类变量赋初值。而实例变量可以在声明变量的时候给实例变量赋初值,在非静态初始化块中以及构造器中赋初值。类变量有两个时机赋初值,而实例变量则可以有三个时机赋初值。当final变量未初始化时系统不会进行隐式初始化,会出现报错。这样说起来还是比较抽象,下面用具体的代码来演示
看上面的图片已经将每种情况整理出来了,这里用截图的方式也是觉得在IDE出现红色出错的标记更能清晰的说明情况。现在我们来将这几种情况归纳整理一下:
- 类变量:必须要在静态初始化块中指定初始值或者声明该类变量时指定初始值,而且只能在这两个地方之一进行指定;
- 实例变量:必要要在非静态初始化块,声明该实例变量或者在构造器中指定初始值,而且只能在这三个地方进行指定。
2.2.2 final局部变量
final局部变量由程序员进行显式初始化,如果final局部变量已经进行了初始化则后面就不能再次进行更改,如果final变量未进行初始化,可以进行赋值,当且仅有一次赋值,一旦赋值之后再次赋值就会出错。下面用具体的代码演示final局部变量的情况:
现在我们来换一个角度进行考虑,final修饰的是基本数据类型和引用类型有区别吗?
final基本数据类型 VS final引用数据类型
通过上面的例子我们已经看出来,如果final修饰的是一个基本数据类型的数据,一旦赋值后就不能再次更改,那么,如果final是引用数据类型了?这个引用的对象能够改变吗?我们同样来看一段代码。
public class FinalExample {
//在声明final实例成员变量时进行赋值
private final static Person person = new Person(24, 170);
public static void main(String[] args) {
//对final引用数据类型person进行更改
person.age = 22;
System.out.println(person.toString());
}
static class Person {
private int age;
private int height;
public Person(int age, int height) {
this.age = age;
this.height =