39

Java中的final关键字

 5 years ago
source link: https://monkeysayhi.github.io/2018/11/06/Java中的final关键字/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

final关键字可以修饰类、方法、变量。本质作用可以理解为“ 声明被修饰对象只读 ”,不同用法对应不同的具体解释。

final类

final类表示该类是完整(可理解为最终版本)的,禁止扩展。final标记会写入class文件的类定义中,在编译期检查,如果发现上游extends了一个final类后,则编译失败,从语法上保证不能extends一个final类。

final类经常用于不可变类的构造中:如果不使用final修饰,且有对子类可见的可变成员变量,则extends该“不可变类”后,子类就变成了可变类。考虑到多态的存在,这种“歧义”非常危险。详见: 实现不可变类时如何禁止子类化?

例:String类、Interger类等:

public final class String

final方法

与final类的语义相似, final方法表示该方法是完整的,禁止重写 。final标记会写入class文件的成员方法定义中,在编译期检查,如果发现继承链上游有函数签名相同的final方法(重写),则编译失败,从语法上保证不能重写一个final方法;同时,在编译期完成对final方法的解析( 静态绑定 )。

例:com.sun.org.apache.bcel.internal.classfile.Signature中的dump方法:

public final void dump(DataOutputStream file)throws IOException
{
  super.dump(file);
  file.writeShort(signature_index);
}

final变量

final成员变量

final成员变量体现了最直观的final语义: final成员变量表示该成员变量只读 (在第一次赋值后就不能再修改)。final标记会写入class文件的成员变量定义中,在编译器和运行期都会进行检查,如果发现第二次修改就编译失败或抛出异常。

如果想实现不可变类,通常建议尽量使用final修饰每一个成员变量(延迟初始化等会违背这一建议)。

如果final成员变量的初始化被收集到该类的构造方法中,则final成员变量初始化之前的变量通常具有内存可见性,但这一性质并不容易应用,不建议利用。详见:一文解决内存屏障。

例:Integer#value:

private final int value;

public Integer(int value){
    this.value = value;
}

显式的用构造方法初始化final成员变量。

常量

如果在成员变量声明时完成初始化(第一次赋值),则该成员变量被JVM视作常量。

对于编译期能确定初始值的常量(如 final int a = 1; ),通常能通过 常量折叠常量传播 等技术,在编译期完成常量的优化和解析。

例: Integer.SIZEInteger.BYTES

@Native public static final int SIZE = 32;

public static final int BYTES = SIZE / Byte.SIZE;

final局部变量

final局部变量也表示该局部变量只读,但与final成员变量不同,final局部变量只是java中的语法糖, 局部变量上的final修饰并不会写入class文件,更无法出现在运行期 。如果局部变量被final修饰,则 编译器在编译时会检查该变量是否有可能发生第二次修改 ,有可能就编译失败;否则,消除final修饰。

例:

n63Izqa.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK