1. 概述

学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。那么我们能不能随意的继承API中提供的类,改写其内容呢?显然这是不合适的。为了避免这种随意改写的情况,Java提供了final 关键字,用于修饰不可改变内容。

  • final: 不可改变,最终的含义。可以用于修饰类、方法和变量。
    • 类:被修饰的类,不能被继承。
    • 方法:被修饰的方法,不能被重写。
    • 变量:被修饰的变量,有且仅能被赋值一次。

2. 使用方式

2.1 修饰类

final修饰的类,不能被继承。

格式如下:

1
2
final class 类名 {
}

代码:

1
2
3
final class Fu {
}
// class Zi extends Fu {} // 报错,不能继承final的类

查询API发现像 public final class Stringpublic final class Mathpublic final class Scanner 等,很多我们学习过的类,都是被final修饰的,目的就是供我们使用,而不让我们所以改变其内容。

2.2 修饰方法

final修饰的方法,不能被重写。 格式如下:

1
2
3
修饰符 final 返回值类型 方法名(参数列表){
//方法体
}

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Fu2 {
public final void show1() {
System.out.println("Fu2 show1");
}
public void show2() {
System.out.println("Fu2 show2");
}
}

class Zi2 extends Fu2 {
// @Override
// public void show1() {
// System.out.println("Zi2 show1");
// }
@Override
public void show2() {
System.out.println("Zi2 show2");
}
}

2.3 修饰变量-局部变量

基本类型的局部变量,被final修饰后,只能赋值一次,不能再更改。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FinalDemo1 {
public static void main(String[] args) {
// 声明变量,使用final修饰
final int a;
// 第一次赋值
a = 10;
// 第二次赋值
a = 20; // 报错,不可重新赋值

// 声明变量,直接赋值,使用final修饰
final int b = 10;
// 第二次赋值
b = 20; // 报错,不可重新赋值
}
}

思考,如下两种写法,哪种可以通过编译?

写法1:

1
2
3
4
5
final int c = 0;
for (int i = 0; i < 10; i++) {
c = i;
System.out.println(c);
}

写法2:

1
2
3
4
for (int i = 0; i < 10; i++) {
final int c = i;
System.out.println(c);
}

根据 final 的定义,写法1报错!写法2,为什么通过编译呢?因为每次循环,都是一次新的变量c。这也是大家需要注意的地方。

2.4 修饰变量-实例成员变量

成员变量涉及到初始化的问题,初始化方式有显示初始化和构造器初始化,只能选择其中一个:

  • 显示初始化(在定义成员变量的时候立马赋值);
1
2
3
public class Student {
final int num = 10;
}
  • 构造器初始化(在构造器中赋值一次)。

    注意:每个构造器中都要赋值一次!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Student {
final int num = 10;
final int num2;

public Student() {
this.num2 = 20;
// this.num2 = 20;
}

public Student(String name) {
this.num2 = 20;
// this.num2 = 20;
}
}

被final修饰的常量名称,一般都有书写规范,所有字母都大写