final修饰符
类似于C#中的sealed
修饰符,用于表示类、方法和变量的不可改变。
1.可修饰范围
- 类
- 变量
- 方法
2.修饰变量
可以修饰
- 成员变量(类变量和实例变量)
- 局部变量
- 形参
2.1 修饰成员变量
成员变量包括:
- 类变量
- 实例变量
成员变量随着类的初始化或对象的初始化而初始化的。
当类执行静态初始化块时可以对类变量赋初始值;当执行普通初始化块、构造器时对实例变量赋予初始值。
对于final修饰的成员变量而言,一旦有了初始值,就不能被重新赋值。
也就是说,如果final修饰的成员变量没有在最开始定义成员变量时指定初始值,也没有再初始化块、构造器中指定初始值,那么该变量就会一直是系统默认分配的值,例如0\false\null等,那么该值将会没有意义。
所以Java语法规定:final修饰的成员变量,必须由程序员显式指定初始值。
final修饰的成员变量可以指定初始值的地方有:
- 类变量:
- 静态初始块(static { } )
- 声明该类变量时指定
- 实例变量:
- 普通初始块
- 声明该变量时指定
- 构造函数中指定
注意:
- final修饰的成员变量只能在一个地方指定,指定之后不能再次赋值
2.2 修饰局部变量
局部变量必须由程序员显式初始化,因此final修饰的局部变量可以在定义时指定初始值,也可以在之后指定(但是只能一次
)。
2.3 修饰形参
final修饰形参后,在方法内就不能再对该参数进行赋值操作,具体的初始化是由系统根据传入的参数来完成的。
publi void test(final int a ){
a= 5; // 报错,不能对final修饰的形参赋值
}
如果执行方法 test(5),那么a= 5;
2.4 修饰引用变类型与基本类型变量的区别
final修饰引用变量类型时,依然不能重新赋值,但是可以改变已经赋值的引用变量的成员变量。
例如:
final Person p = new Person(age:45);
p.setAge(12); // 可以改变person变量的age成员变量
// 此时报错,final修饰的引用变量不可重新赋值
p = null;
2.5 final与直接量
直接量:指在程序中通过源代码直接给出的值,也就是该变量在编译时就可确定下来,编译器会把程序中所有用到该变量的地方直接替换成该变量的值。
满足以下三个条件,这个final变量就是一个直接量:
- 使用final修饰
- 定义该final变量时就指定了初始值
- 该初始值可以在编译时就可以确定下来
举例:
String s1 = "HelloWorld";
String s2 = "Hello" + "World";
s1==s2; // true
String s3 = "Hello";
String s4 = "World";
String s5 = s3 +s4;
s1==s5; // false
Java中的字符串有一个常量池的概念,Java会有常量池来管理曾经使用过的字符串直接量,编译器在编译期间就能知道 s2="HelloWorlad",所以会让s2直接指向常量池中的"HelloWorld"字符串,所以s1 和s2的指向相同,所以s1 == s2。
第二种情况,s5的值是由s3和s4进行连接运算后得到,因为s3和s4是两个普通变量,而不是一个直接量,因此编译器无法在编译期间确定s5的值,也就是说无法让s5指向常量池中的"HelloWorld",所以s1 == s5结果不成立。
所以,如果想要让s1==s5结果成立,只要将s3和s4变为直接量,即使用final修饰这两个变量即可。
3.修饰方法
final修饰方法主要是不希望子类重写此方法。
4.修饰类
final修饰的类不可以有子类(不可以被继承)。
- final类中的所有方法都会被隐式指定为final方法