Java final 修饰符知识点总结
final 从字面上理解含义为“最后的,最终的”。在 Java 中也同样表示出此种含义。
final 可以用来修饰变量(包括类属性、对象属性、局部变量和形参)、方法(包括类方法和对象方法)和类。
final 修饰类:
final 修饰类即表示此类已经是“最后的、最终的”含义。因此,用 final 修饰的类不能被继承,即不能拥有自己的子类。
如果试图对一个已经用 final 修饰的类进行继承,在编译期间或发生错误。
final 修饰方法:
final 修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个 final 修饰的方法)。
此处需要注意的一点是:因为重写的前提是子类可以从父类中继承此方法,如果父类中 final 修饰的方法同时访问控制权限为 private,
将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与 final 的矛盾,而是
在子类中重新定义了新的方法。
public class B extends A {
public static void main(String[] args) {
}
public void getName() {
}
}
class A {
/**
* 因为private修饰,子类中不能继承到此方法,因此,子类中的getName方法是重新定义的、
* 属于子类本身的方法,编译正常
*/
private final void getName() {
}
/* 因为pblic修饰,子类可以继承到此方法,导致重写了父类的final方法,编译出错
public final void getName() {
}
*/
}
final 修饰变量:
final 修饰的变量表示此变量是“最后的、最终的”含义。一旦定义了 final 变量并在首次为其显式初始化后,final 修饰的变量值不可被改变。
这里需要注意以下几个问题:
final 修饰的变量,无论是类属性、对象属性、形参还是局部变量,这些变量都是需要进行显式初始化(即为其显式指定初始值)。
对于 final 修饰的形参,由于是实参传递过来的,很好理解。
对于 final 修饰的局部变量,与未用 final 修饰的变量一样,都是需要显式初始化。即局部变量都是需要显式初始化的。
对于一般的类属性和对象属性,由类和对象的初始化过程中可以看出,首先都进行了默认初始化。然后对有显式赋值的变量才再进行显式初始化。
但对 final 修饰的类属性和对象属性而言,如果不显式初始化,其默认将是进行默认初始化后的值,这与 final 本身出发点矛盾,因此,Java 语法规定:
final 修饰的类属性和变量属性必须要进行显式初始化赋值。
另外,无论对于基本数据类型还是引用数据类型,final 修饰的变量都是首次显式初始化后值都不能修改。对于基本数据类型,很好理解。对于引用
数据类型,引用变量指向的是实际的对象,但其存储的是所指向对象的地址,因此,其值不能修改并不意味着其所指向的对象不能修改。
final 修饰变量后导致的“宏替换”/"宏变量" 问题
Java 中宏变量 / 宏替换指的是 java 代码中在编译期某些变量能够直接被其本身的值所替换,编译到.class 文件中。因此,编译后的.class 文件中已经不存在此变量了。
在 String 类型的变量中,有时候经常遇到如下情况:
public class Test {
public static void main(String[] args) {
String country = "China";
String name = "qqyumidi";
String userInfo = country + name; //编译后此处依然是country和name变量
String user = "China" + "qqyumidi"; //编译后此处直接变成Chinaqqyumidi
}
}
在上述代码中的第 9 行,编译后的变量结果直接为 Chinaqqyumidi。而第 8 行代码中,由于 country 和 name 都是普通的变量,编译器无法在编译时直接确定 userInfo 的值,因此
此处编译后结果不直接是 Chinaqqyumidi。
但是,如果希望第 8 行中的代码在编译期直接就能表示为 Chinaqqyumidi,就需要用到 final 修饰符对 country 和 name 变量进行修饰。
原因:final 修饰符修饰的变量在由于其本身的特性,在编译期就能直接确定其值,且此值不可变。在编译过程中,可以直接将其变量直接转换成其值本身去表示。
public class Test {
public static void main(String[] args) {
final String country = "China";
final String name = "qqyumidi";
String userInfo = country + name; //编译后此处直接是Chianqqyumidi
}
}