final关键字的使用
final关键字
一、final的使用概述
-
1、加在类上表示类不可被继承;
使用场景:自定义工具类的时候,不需要再次来进行重写,或者是说我们只是想给工具类起一个自己公司使用的别名。
-
2、加载方法上,表示方法不能够被重写;
-
3、加上变量上,表示成员变量的值不可以被修改。对于基本类型变量来说,不可能被修改;对于引用类型变量来说,引用所指向堆内存中的地址不能够发生改变。
下面分别演示其中的使用场景
二、final作用在类上
自定义类的两种使用方式:
1、继承使用final
/**
* @Description CollectionUtils源自于:org.springframework.util.CollectionUtils
* @Author liguang
* @Date 2022/01/03/23:37
*/
public final class CollectionUtil extends CollectionUtils {
}
这里可以自定义类,并用final关键字来进行属性!表示的是禁止有类来进行继承
2、自定义类使用final
不想这个类再来被继承,被其他类使用。
public final class Node<T> {
private T data;
private Node nex;
// getter/setter方法
}
三、final作用在方法上
1、利用模板模式的设计方法演示
final修饰的方法子类不可以重写,但是可以子类继承之后可以使用。看下示例:
抽象父类
/**
* @Description 游戏抽象父类
* @Author liguang
* @Date 2021/12/26/18:17
*/
public abstract class Game {
private void login(){
System.out.println("开始登录游戏...........");
}
/**
* 钩子函数决定是否来切换模式
*/
public abstract Boolean hook();
/**
* 有很多场景模式来进行切换
*/
public abstract void switchModel();
private void play(){
System.out.println("开始来玩游戏...........");
}
private void end(){
System.out.println("游戏结束.............");
}
/**
* 模板模式。加上final关键字,禁止子类重写方法
* 这里已经定义好了流水线过程!只需要子类来按照具体的模式来进行书写即可
*/
public final void startGame(){
login();
if (hook()){
switchModel();
}
play();
end();
}
}
虽然说子类不可以来进行重写startGame方法,但是子类可以来访问startGame方法。
子类DXC
/**
* @Description 地下城游戏
* @Author liguang
* @Date 2021/12/26/18:23
*/
public class DXC extends Game{
/**
* 钩子函数,表示是否切换游戏模式
* @return
*/
@Override
public Boolean hook() {
return Boolean.FALSE;
}
@Override
public void switchModel() {
}
}
子类LOL
/**
* @Description LOL游戏
* @Author liguang
* @Date 2021/12/26/18:22
*/
public class LOL extends Game{
/**
* 钩子函数,表示是否切换游戏模式
* @return
*/
@Override
public Boolean hook() {
return Boolean.FALSE;
}
@Override
public void switchModel() {
System.out.println("正常玩游戏............");
}
}
子类WZRX
/**
* @Description 王者荣耀游戏
* @Author liguang
* @Date 2021/12/26/18:21
*/
public class WZRX extends Game{
/**
* 钩子函数,表示是否切换游戏模式
* @return
*/
@Override
public Boolean hook() {
return Boolean.TRUE;
}
@Override
public void switchModel() {
System.out.println("切换到娱乐模式......................");
}
}
测试类
@Test
public void testGetBeanForType() {
final Map<String, Game> beanNameForValueMap = GlobalSpringApplicationContext.getBeanForType(Game.class);
beanNameForValueMap.forEach((k,v)->{
v.startGame();
System.out.println("+++++++++++++++++++");
});
}
那么可以看到每个子类的输出:
开始登录游戏...........
开始来玩游戏...........
游戏结束.............
+++++++++++++++++++
开始登录游戏...........
开始来玩游戏...........
游戏结束.............
+++++++++++++++++++
开始登录游戏...........
切换到娱乐模式......................
开始来玩游戏...........
游戏结束.............
+++++++++++++++++++
定义了一套流水线工程,子类重写过程中只需要根据自己的需求来进行实现即可。
四、final作用在变量和成员属性上
1、final作用在变量上
public void forEach(final Person person){
// xxxxxxx
}
禁止在方法体中操作的时候,改变了person的地址值。因为可能会存在着重新new一个Person类型对象的可能来进行覆盖person原有的值。这个源码中经常有。
所以为了防止在代码中对一个对象来进行修改,只是为了修改对象其中的属性而已,那么建议加上final关键字来进行修饰。
2、作用在成员变量上
这个倒是在spring中经常可以看到
@Controller
@AllArgsConstructor
public class UserController {
private final UserService userService;
}
可以看到使用final修饰的成员变量,可以这么来写。具体的有三种使用方式
1、直接赋值
在后面直接进行赋值:
public class Animal {
private final String str = "hello";
}
一旦被修饰之后,对象的地址值无法进行修改,但是对象的属性值是可以改变的。
2、静态初始化
使用静态初始化
public class Animal {
private static final String str;
static {
str = "";
}
}
但是这种使用方式要求:成员变量要使用static+final关键字来进行修饰。
3、有参构造
使用有参构造方法进行注入:
public class Animal {
private final String str;
public Animal(String str) {
this.str = str;
}
}
可以看到这种使用方式,构造中必须要含有final修饰的成员变量的方法。可以看到final定义的变量必须要经过初始化之后才可以来进行使用。
所以这里印出来一个问题:
public class Animal {
private final String str = "hello";
public Animal(String str) {
this.str = str;
}
}
看一下测试,最终的str到底是什么?但是发现,这样子来写,idea直接报编译时异常。
Cannot assign a value to final variable 'str'
说明了final修饰的成员变量直接进行赋值后,就不会参与构造了;但是没有进行赋值,那么就必须参数构造方法中来。
五、final总结
作用范围 | 说明 |
---|---|
作用在类上 | 不允许类继承 |
作用在方法上 | 不允许重写,但是可以使用 |
作用在局部变量上 | 1、为引用类型时候,不允许修改引用类型的地址值;2为基础类型时,不允许修改普通的值 |
作用在成员变量上 | 1、直接赋值;2、在构造中进行赋值。注意:1和2不能够同时都来进行操作 |