<>一、final 的基本用法

<>1、修饰类

final修饰一个类时,表示该类不能继承。比如下面的写法就是错误的:
final class A{ } class B extends A{ }

而且对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。有抽象方法的abstract类被继承时,其中的方法必须被子类Override,而final不能被Override。

<>2、修饰方法

final 修饰的方法不能被覆盖或者重写,这也确保了父类中的方法被子类继承后发生异变(即重写)。也就是说,我们如果用 final
修饰某个方法,这个方法就是稳定的,不变的。
class A{ final public void printHelloWorld(){ System.out.println("Hello,world!"
); } } class B extends A{ @Override public void printHelloWorld(){ System.out.
println("Hello,moon!"); } }
上面这个子类的printHelloWorld()方法就会报错,因为父类中已经用 final
修饰过了。但是想要重写也是可以的,如果父类中final修饰的方法同时访问控制权限为private
,将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与final的矛盾,而是在子类中重新定义了新的方法。比如:
class A{ private final void printHelloWorld(){ System.out.println(
"Hello,world!"); } } class B extends A{ public void printHelloWorld(){ System.
out.println("Hello,moon!"); } }
这就是可以的,另外,类的private方法会隐式地被指定为final方法。因此,IDEA 会建议我们去掉关键字final,像下面这样:

<>3、修饰变量

final成员变量表示常量,只能被赋值一次,赋值后值不再改变。

当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后就不可以指向其它对象了,但该引用所指向的对象的内容是可以发生变化的。

final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。比如:
public class FinalTest01 { public static void main(String[] args) { final int a
= 10; a = 11; //报错 final B bb = new B(20); bb.b = 30; bb = new B(30); //报错 } }
class B { int b; public B(int b) { this.b = b; } }
<>二、final 的优化问题

可以看一下这个程序:
public class FinalTest01 { public static void main(String[] args) { String a =
"hello-world"; final String b = "hello-"; String b1 = "hello-"; String c = b+
"world"; String d = b1+"world"; System.out.println(c == a); System.out.println(d
== a); } }
它的输出为:

true
false

为什么第一个比较结果为true,而第二个比较结果为fasle?这里面就是final变量和普通变量的区别了,当final变量是基本数据类型以及String类型
时,如果在编译期间能知道它的确切值,则编译器会把它当做编译期常量使用。也就是说在用到该final变量的地方,相当于直接访问的这个常量,不需要在运行时确定。
当然这里也同样涉及编译器对 String 类型的优化,不过这个不是这里的重点,不再赘述。

<>三、final 修饰参数

看下一段代码:
public class FinalTest01 { public static void main(String[] args) {
FinalTest01 finalTest01= new FinalTest01(); int a = 10; finalTest01.changePer(a)
; System.out.println(a); } public void changePer(final int i){ i++;// 会报错,
System.out.println(i); } }
因为 changePer() 中的参数是 final 修饰过的,所以该参数在函数体内就无法被改变了。因为Java参数传递采用的是值传递
,对于基本类型的变量,相当于直接将该变量的值进行了赋值。因此就算没有final修饰,在方法内部改变了变量i的值,也不会main 函数中的i。这在 Java
中是非常关键的点。值传递是 Java 的一大特性,这是 Java 设计的思想,即把程序安全交给了 Java 的设计师,而不是程序员。这也是和
C++非常大的一个区别。当然这也和本篇博客的主题没有太大关系,不再赘述。

<>四、final 修饰的变量和常量的关系

这个问题比较复杂,我会另开辟一篇文章专门讨论。

全文完,感谢你的阅读。

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信