1、final使用
(1)final变量
final变量有成员变量或者是本地变量(方法内的局部变量),在类成员中final经常和static一起使用,作为类常量使用。其中类常量必须在声明时初始化,final成员常量可以在构造函数初始化。
public class Main {
public static final int i; //报错,必须初始化 因为常量在常量池中就存在了,调用时不需要类的初始化,所以必须在声明时初始化
public static final int j;
Main() {
i = 2;
j = 3;
}
}
就如上所说的,对于类常量,JVM会缓存在常量池中,在读取该变量时不会加载这个类。
public class Main {
public static final int i = 2;
Main() {
System.out.println("调用构造函数"); // 该方法不会调用
}
public static void main(String[] args) {
System.out.println(Main.i);
}
}
(2)final修饰基本数据类型变量和引用
@Test
public void final修饰基本类型变量和引用() {
final int a = 1;
final int[] b = {1};
final int[] c = {1};
// b = c;报错
b[0] = 1;
final String aa = "a";
final Fi f = new Fi();
//aa = "b";报错
// f = null;//报错
f.a = 1;
}
final方法表示该方法不能被子类的方法重写,将方法声明为final,在编译的时候就已经静态绑定了,不需要在运行时动态绑定。final方法调用时使用的是invokespecial指令。
class PersonalLoan{
public final String getName(){
return"personal loan”;
}
}
class CheapPersonalLoan extends PersonalLoan{
@Override
public final String getName(){
return"cheap personal loan";//编译错误,无法被重载
}
public String test() {
return getName(); //可以调用,因为是public方法
}
}
(3)final类
final类不能被继承,final类中的方法默认也会是final类型的,java中的String类和Integer类都是final类型的。
class Si{
//一般情况下final修饰的变量一定要被初始化。
//只有下面这种情况例外,要求该变量必须在构造方法中被初始化。
//并且不能有空参数的构造方法。
//这样就可以让每个实例都有一个不同的变量,并且这个变量在每个实例中只会被初始化一次
//于是这个变量在单个实例里就是常量了。
final int s ;
Si(int s) {
this.s = s;
}
}
class Bi {
final int a = 1;
final void go() {
//final修饰方法无法被继承
}
}
class Ci extends Bi {
final int a = 1;
// void go() {
// //final修饰方法无法被继承
// }
}
final char[]a = {'a'};
final int[]b = {1};
final class PersonalLoan{}
class CheapPersonalLoan extends PersonalLoan { //编译错误,无法被继承
}
@Test
public void final修饰类() {
//引用没有被final修饰,所以是可变的。
//final只修饰了Fi类型,即Fi实例化的对象在堆中内存地址是不可变的。
//虽然内存地址不可变,但是可以对内部的数据做改变。
Fi f = new Fi();
f.a = 1;
System.out.println(f);
f.a = 2;
System.out.println(f);
//改变实例中的值并不改变内存地址。
Fi ff = f;
//让引用指向新的Fi对象,原来的f对象由新的引用ff持有。
//引用的指向改变也不会改变原来对象的地址
f = new Fi();
System.out.println(f);
System.out.println(ff);
}
2、final关键字的知识点
(1)final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。final变量一旦被初始化后不能再次赋值。
(2)本地变量必须在声明时赋值。 因为没有初始化的过程在匿名类中所有变量都必须是final变量。
(3)final方法不能被重写, final类不能被继承接口中声明的所有变量本身是final的。类似于匿名类
(4)final和abstract这两个关键字是反相关的,final类就不可能是abstract的。
(5)final方法在编译阶段绑定,称为静态绑定(static binding)。
将类、方法、变量声明为final能够提高性能,这样JVM就有机会进行估计,然后优化。
3、final方法的好处:
(1)提高了性能,JVM在常量池中会缓存final变量.
(2)final变量在多线程中并发安全,无需额外的同步开销.
(3)final方法是静态编译的,提高了调用速度.
(4)final类创建的对象是只可读的,在多线程可以安全共享.