5.final的三种用法

159 阅读3分钟

final的三种用法

修饰变量、方法、类

1.修饰变量

一旦赋值不能修改

为什么?

  1. 设计角度:更清晰,不容易出错
  2. 线程安全:不可变的对象是线程安全的,不需要我们额外进项同步处理,这些开销是没有的,如果final修饰的是基本数据类型,那么它具备了不可变这个性质,所以自动保证了线程安全

赋值时机

  • 成员变量,类中非static

    • public class a{
          private final int finalVar=0;
      }
      
    • public class a{
          private final int finalVar;
          public a(){
              finalVar=0;
          }
      }
      
    • public class a{
          private final int finalVar;
          {
              finalVar=0;
          }
      }
      
    • 必须赋值

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

      • public class BlankFinal {
            //灵活
            private final int a;
        ​
            public BlankFinal() {
                this.a = 0;
            }
        ​
            public BlankFinal(int a) {
                this.a = a;
            }
        }
        

        在这个代码中,我们有一个 private final 的 int 变量叫作 a,该类有两个构造函数,第一个构造函数是把 a 赋值为 0,第二个构造函数是把 a 赋值为传进来的参数,所以你调用不同的构造函数,就会有不同的赋值情况。这样一来,利用这个规则,我们就可以根据业务去给 final 变量设计更灵活的赋值逻辑。 所以利用空白 final 的一大好处,就是可以让这个 final 变量的值并不是说非常死板,不是绝对固定的,而是可以根据情况进行灵活的赋值,只不过一旦赋值后,就不能再更改了。

  • 静态变量

    • 2种
    • public class StaticFieldAssignment1 {
          private static final int a = 0;
      }
      
    • public class StaticFieldAssignment1 {
          private static final int a;
      ​
          static {
              a = 0;
          }
      }
      
    • 注意:static 的 final 变量不能在构造函数中进行赋值。
  • 局部变量

    • 1种:在使用之前必须对它进行赋值

    • public class LocalVarAssignment1 {
          public void foo() {
              final int a = 0;
          }
      }
      ​
      class LocalVarAssignment2 {
          public void foo() {
              final int a;
          }
      }
      ​
      class LocalVarAssignment3 {
          public void foo() {
              final int a;
              a = 0;
              System.out.println(a);
          }
      }
      
    • 特殊用法:final修饰参数

      • public class FinalPara {
            public static void withFinal(final int a) {
                System.out.println(a);
            }
        }
        

2.修饰方法

  • 提高效率,因为Java版本中会把final方法转为内嵌使用,可以消除方法调用的开销,提高程序运行效率,不过后期Java版本JVM会对此自动进行优化,不需要程序员使用final修饰方法进行这些优化,即使使用也不会有性能提升

  • 把这个方法锁定,任何继承类补鞥呢修改这个方法含义,不可以被重写

  • 构造方法不允许被final修饰

  • 注意:final的private方法,其他范围修饰符根本不能用

    • public class PrivateFinalMethod {
          private final void privateEat() {
      ​
          }
      }
      ​
      class SubClass2 extends PrivateFinalMethod {
          private final void privateEat() {
              
          }
      }
      

      这不是真正重写,只是方法名碰巧相同,加上@Override就报错

3.修饰类

  • 不允许其他人继承,保证线程安全
  • 给某个类加上了 final 关键字,这并不代表里面的成员变量自动被加上final。事实上,这两者之间不存在相互影响的关系,也就是说,类是 final 的,不代表里面的属性就会自动加上 final。
  • 其实在 final 的类里面,所有的方法,不论是 public、private 还是其他权限修饰符修饰的,都会自动的、隐式的被指定为是 final修饰的。

4.如果必须使用final方法或类,请说明原因

未来代码维护者可能不理解为什么这里使用final,使用后是有影响的,把final应用在更小范围的类或方法上,更小的影响

\