final的基本使用
-
修饰类: 修饰类的时候,该类不可以被继承,final类中所有的方法隐式为final。如果类被final修饰,但是想复用该类方法,并且想加上自己的方法,可以通过组合来实现,在自己的类中,将final修饰的类放进去
class MyString{ private String innerString; // 支持老的方法 public int length(){ return innerString.length(); // 通过innerString调用老的方法 } // 添加新方法 public String toMyString(){ //... } }
-
修饰方法:
- private修饰的方法都隐式的指定为final:当父类存在一个private修饰的方法test,子类有一个public修饰的方法test。通过子类向上转型获取父类,调用test方法是不可执行的。private所修饰的方法是隐式的final,也就是无法被继承,所以更不用说是覆盖了,所以子类中的test方法其实是子类的新成员方法而已。
- 且final修饰的方法是可以被重载的。
-
修饰参数: Java允许在参数列表中以声明的方式将参数指明为final,这意味这你无法在方法中更改参数引用所指向的对象。这个特性主要用来向匿名内部类传递数据
-
**修饰变量:**final修饰的变量,只有在初始化之后无法被变更。
-
final修饰的变量并非都是编译期变量
public class Test { //编译期常量 final int i = 1; final static int J = 1; final int[] a = {1,2,3,4}; //非编译期常量 Random r = new Random(); final int k = r.nextInt(); public static void main(String[] args) { } }
-
static final: 一个既是static又是final 的字段只占据一段不能改变的存储空间,它必须在定义的时候进行赋值,否则编译器将不予通过,一旦被初始化之后便不会改变。且static修饰的字段不属于某个对象,而是属于这个类。
import java.util.Random; public class Test { static Random r = new Random(); final int k = r.nextInt(10); static final int k2 = r.nextInt(10); public static void main(String[] args) { Test t1 = new Test(); System.out.println("k="+t1.k+" k2="+t1.k2); Test t2 = new Test(); System.out.println("k="+t2.k+" k2="+t2.k2); } }
-
blank final: 被声明为final但又没有给出定值的字段,但是必须在该字段被使用之前被赋值,这给予我们两种选择:在定义初赋值,或者在构造器进行赋值。
-
final重排序规则
基本数据类型:
final域写
:禁止final域写与构造方法重排序,即禁止final域写重排序到构造方法之外,从而保证该对象对所有线程可见时,该对象的final域全部已经初始化过。构造函数return之前,插入一个storestore屏障。这个屏障可以禁止处理器把final域的写重排序到构造函数之外。final域读
:禁止初次读对象的引用与读该对象包含的final域的重排序。处理器会在读final域操作的前面插入一个LoadLoad屏障。读final域的重排序规则可以确保:在读一个对象的final域之前,一定会先读这个包含这个final域的对象的引用
引用数据类型:
额外增加约束
:禁止在构造函数对一个final修饰的对象的成员域的写入与随后将这个被构造的对象的引用赋值给引用变量重排序