1、final修饰变量
当final修饰变量时,变量的值不能被改变。
对于final修饰的基本类型或String类型变量:
1、变量在定义时已经进行字面量赋值,编译器会在编译期进行计算,在class文件中以常量的形式存在,从而节省运行期的开销,我们称之为编译期常量;
2、以方法的形式给变量赋值,则变量值需要在运行期才能确定,因此变量的值不恒定。假设变量为a,每当对象创建的时候,方法就会被调用,从而给变量a赋值,因此每个对象的a变量值都不一样。若声明a变量时加上修饰符static,此时所有对象共享同一a变量,因此当类被加载时调用方法给变量a赋值,之后无论创建多少个对象的a变量值都不会变化;
例:
public class FinalData {
final int a = (int) (Math.random() * 10);
static final int b = (int) (Math.random() * 10);
public static void main(String[] args) {
FinalData f1 = new FinalData();
FinalData f2 = new FinalData();
System.out.println(f1.a);
System.out.println(f2.a);
System.out.println(f1.b);
System.out.println(f2.b);
}
}
上述代码的输出结果是1、8、7、7;
对于final修饰的引用类型:
引用类型变量中存储的是对象的句柄(引用),因此加上final后固定的只是变量指向的对象不变,对象中各成员变量的数值依然是可以改变的。
final字段的赋值:
1、在字段声明时赋值;
2、在构造函数中赋值;
方法的自变量用final修饰:
我们只能使用自变量,不能修改自变量
2、final修饰方法
当final修饰方法时主要效果有两个:
1、子类不能重写覆盖该方法;
2、通过内嵌机制提高效率;
内嵌机制:
当final方法被调用时,编译器会自动将该方法被调用处的调用语句替换成该方法的实体,再形成class。
例:
final void fun(){System.out.println("fun");}
void testFun(){
for(int i = 0; i < 1000; i++){
fun(); //此处将会被编译器替换为 System.out.println("fun");
}
}
这种内嵌机制只适用于调用的方法代码量较少的情况,若方法体积较大,那么编译器在编译时耗费的时间比代码调用的时间长,反而降低效率。Java 编译器能自动检测这些情况,并相对智能的决定是否嵌入一个final 方法。然而,最好不要完全相信编译器能正确的作出判断,所以通常在代码量较少或者不希望代码被重写的情况下,才用final修饰方法(注:private方法默认是final的)
3、final修饰类
final修饰类时类不能被继承,类中的成员变量不会受到影响,类中的所有方法默认都为final,编译器此时有相同的效率选择。