清华教授!想要吃透final的各种用法与意义?看这篇笔记就够了

final的各种用法与意义

final 是 Java 中的一个关键字,简而言之,final 的作用意味着“这是无法改变的”。

不过由于 final 关键字一共有三种用法,它可以用来修饰变量、方法或者类,而且在修饰不同的地方时,效果、含义和侧重点也会有所不同,所以我们需要把这三种情况分开介绍。

final 修饰变量

关键字 final 修饰变量的作用是很明确的,那就是意味着这个变量一旦被赋值就不能被修改了,也就是说只能被赋值一次,直到天涯海角也不会“变心”。如果我们尝试对一个已经赋值过 final 的变量再次赋值,就会报编译错误。

public class FinalVariable {
    public final int objVar = 0;
    public static final int clsVar = 0;
    public static void main(String[] args) {
        FinalVariable finalVariable = new FinalVariable();
        finalVariable.objVar = 1;
        clsVar = 1;
    }
}

在这个例子中,我们有两个 final 修饰的 in,然后在 main 函数中尝试去修改它的值,此时会报编译错误,所以这体现了 final 修饰变量的一个最主要的作用:一旦被赋值就不能被修改了。

目的

看完了它的作用之后,我们就来看一下使用 final 的目的,也就是为什么要对某个变量去加 final 关键字呢?主要有以下两点目的。

  1. 第一个目的是出于设计角度去考虑的,比如我们希望创建一个一旦被赋值就不能改变的量,那么就可以使用 final 关键字。比如声明常量的时候,通常都是带 final 的
  2. 第二个目的是从线程安全的角度去考虑的。不可变的对象天生就是线程安全的,所以不需要我们额外进行同步等处理,这些开销是没有的。如果 final 修饰的是基本数据类型,那么它自然就具备了不可变这个性质,所以自动保证了线程安全,这样的话,我们未来去使用它也就非常放心了。

赋值时机

下面我们就来看一下被 final 修饰的变量的赋值时机,变量可以分为以下三种:

  1. 成员变量,类中的非 static 修饰的属性;
  2. 静态变量,类中的被 static 修饰的属性;
  3. 局部变量,方法中的变量。

成员变量

成员变量指的是一个类中的非 static 属性,对于这种成员变量而言,被 final 修饰后,它有三种赋值时机(或者叫作赋值途径)。

  1. 第一种是在声明变量的等号右边直接赋值,例如:
public class FinalFieldAssignment1 {
    private final int finalVar = 0;
}
  1. 第二种是在构造函数中赋值,例如:
class FinalFieldAssignment2 {
    private final int finalVar;
    public FinalFieldAssignment2() {
        finalVar = 0;
    }
}
  1. 第三种就是在类的构造代码块中赋
class FinalFieldAssignment3 {
    private final int finalVar;
    {
        finalVar = 0;
    }
}

需要注意的是,这里讲了三种赋值时机,我们必须从中挑一种来完成对 final 变量的赋值。如果不是 final 的普通变量,当然可以不用在这三种情况下赋值,完全可以在其他的时机赋值;或者如果你不准备使用这个变量,那么自始至终不赋值甚至也是可以的。但是对于 final 修饰的成员变量而言,必须在三种情况中任选一种来进行赋值,而不能一种都不挑、完全不赋值,那是不行的,这是 final 语法所规定的。

下面讲解一种概念:“空白 final”。如果我们声明了 final 变量之后,并没有立刻在等号右侧对它赋值,这种情况就被称为“空白 final”。这样做的好处在于增加了 final 变量的灵活性,比如可以在构造函数中根据不同的情况,对 final 变量进行不同的赋值,这样的话,被 final 修饰的变量就不会变得死板,同时又能保证在赋值后保持不变。

/**
 * 描述:     空白final提供了灵活性
 */
public class BlankFinal {
    //空白final
    private final int a;
    //不传参则把a赋值为默认值0
    public BlankFinal() {
        this.a = 0;
    }
    //传参则把a赋值为传入的参数
    public BlankFinal(int a) {
        this.a = a;
    }
}

在这个代码中,我们有一个 private final 的 int 变量叫作 a,该类有两个构造函数,第一个构造函数是把 a 赋值为 0,第二个构造函数是把 a 赋值为传进来的参数,所以你调用不同的构造函数,就会有不同的赋值情况。

这样一来,利用这个规则,我们就可以根据业务去给 final 变量设计更灵活的赋值逻辑。所以利用空白 final 的一大好处,就是可以让这个 final 变量的值并不是说非常死板,不是绝对固定的,而是可以根据情况进行灵活的赋值,只不过一旦赋值后,就不能再更改了。

静态变量

静态变量是类中的 static 属性,它被 final 修饰后,只有两种赋值时机。

第一种同样是在声明变量的等号右

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值