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不能够同时都来进行操作
posted @ 2022-01-03 23:58  雩娄的木子  阅读(105)  评论(0编辑  收藏  举报