一、final关键字概述
final关键字具有最终或不可改变的含义,可用于修饰类、变量、方法。因此被final修饰的类、变量、方法具有以下特征:
--final修饰的类不能被继承;
--final修饰的方法不能被子类重写;
--final修饰的变量(成员变量和局部变量)是常量,只能赋予一次。
二、使用方式
1)修饰类,格式如下:
public final class 类名称 { // ... }
2)修饰方法,格式如下:
修饰符 final 返回值类型 方法名称(参数列表) { // ...
}
3)修饰变量
成员变量
final修饰的成员变量初始化(赋值)有两种方式,一种是直接赋值,另一种是通过构造方法赋值,二者选其一。
a.直接赋值代码示例:
package cn.sjk.study.java.final; public class Person { //方法1:直接赋值 private final String name = "sjk"; }
b.通过构造方法赋值代码示例:
package cn.sjk.study.java.final; public class Person { //方法2:定义时没有赋值,通过构造方法来赋值 private final String name; public Person(String name) { this.name = name; } }
注意:当使用构造方法对final修饰的成员变量赋值时,必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值,代码示例:
package cn.sjk.study.java.final; public class Person { private final String name; //下面的无参构造方法和带参构造方法里都必须对final的成员变量进行赋值,否则编译不通过 public Person() { name = "sjk"; } public Person(String name) { this.name = name; } }
实际开发中,初始化非final修饰的成员变量除了上面两种方式外,我们还会通过set()方法对其赋值,但是对final修饰的成员变量,只能通过上面两种方法中的任意一种,否则赋值编译会报错。如以下操作不合法:
package cn.sjk.study.java.final; public class Person { private final String name; //对于final修饰的变量使用这种赋值方式不可行 public void setName(String name) { this.name = name; } }
局部变量-基本类型
基本类型的局部变量,被final修饰后,只能复制一次,不能再改变。代码示例如下
package cn.sjk.study.java.final; public class FinalDemo { public static void main(String[] args) { //声明变量,使用final修饰 final int age; //第一次赋值 age = 18; //第二次赋值 age =28; //报错,不可重复赋值 //声明变量,直接赋值,使用final赋值 final int age = 18; //第二次赋值 age = 28; //报错,不可重复赋值 } }
局部变量-引用类型
引用类型的局部变量,被fianl修饰后,只能指向一个对象,地址不能再改变。但不影响对向内部的成员变量值的修改,代码示例如下:
public class FinalDemo2 { public static void main(String[] args) { //创建Person对象 final Person p = new Person(); //创建另一个person对象 p = new Person(); //报错,指向了新对象,地址改变 //调用setName方法 p.setName("sjk"); //可以修改 } }
思考,下面两种写法,哪一种可以编译通过?
写法1:
final int age = 0; for (int i = 0; i < 10; i++) { age = i; System.out.println(age); }
写法2:
for (int i = 0; i < 10; i++) { final int age = i; System.out.println(age); }
根据 final 的定义,写法1报错!写法2,为什么通过编译呢?因为每次循环,都是一次新的变量age。这也是大家 需要注意的地方。