final声明变量可以保证在构造器函数返回之前,这个变量的值已经被设置。详细可以看final声明的重排序规则。分为三种情况:
final int[] intArray;
,intArray不允许再引用其他对象,但是intArray内的int值却可以被修改)。final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。接口中声明的所有变量本身是final的。另外,final变量定义的时候,可以先声明,而不给初值,这种变量也称为final空白,无论什么情况,编译器都确保空白final在使用之前必须被初始化。但是,final空白在final关键字的使用上提供了更大的灵活性。比如:
private final int E; //final空白,必须在初始化对象的时候赋初值
public Test3(int x) {
E = x;
}
final声明的方法不可以被重写,但可以被继承。final不能用于修饰构造方法。使用final方法的原因有二: 第一、把方法锁定,防止任何继承类修改它的意义和实现。 第二、高效。因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。
final声明的类不可以被继承,final类中的方法默认是final的。但是成员变量却不一定是final的,必须额外给成员变量声明为final。注意:一个类不能同时被abstract和final声明。 在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会被扩展,那么就设计为final类。比如Java中有许多类是final的,譬如String, Interger以及其他包装类。
final域的重排序规则,编译器和处理器要遵守两个重排序规则:
而普通域是可以被重排序到构造器之外的。重排序可能导致一个线程看到一个对象的时候,这个对象还没有初始化完毕(部分初始化或者完全没有经过初始化,即读取到对象为null)。 下面,我们通过一些示例性的代码来分别说明这两个规则(在这里通过外部方法不安全的发布了对象,即对象还没有构造完成就发布了对象,这种例子也就仅仅起到说明作用):
public class FinalExample {
int i; //普通变量
final int j; //final变量
static FinalExample obj;
public void FinalExample () { //构造函数
i = 1; //写普通域
j = 2; //写final域
}
public static void writer () { //写线程A执行
obj = new FinalExample ();
}
public static void reader () { //读线程B执行
FinalExample object = obj; //读对象引用
int a = object.i; //读普通域
int b = object.j; //读final域
}
}
这里假设一个线程A执行writer ()方法,随后另一个线程B执行reader ()方法。下面我们通过这两个线程的交互来说明这两个规则。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。