【Java修饰符之二】探讨Java中final的三种使用场景和总结

final修饰符知识总结


final修饰符的概念:
final修饰符是Java中的一个保留字,可以有三种使用场景,每种场景可以由对应不一样的功能:

  • 修饰类
  • 修饰方法
  • 修饰变量(成员变量,局部变量)

修饰类


final修饰符是可以用来修饰类的,被final所修饰的类称为final类,final类与普通的类之间在功能上并没有什么不同,只是final类不允许被继承。

特性:

  • final类不允许被继承(意味着该类的设计永久不需要得到改变,不需要被拓展)
public final Class Demo {}
Class SonofDemo extends Demo {}     //compilation error : cannot inherit form final class

延伸:

  • 这里我们说类可以被final所修饰,稍微联想一下,那么抽象类和接口可以被final所修饰吗?修饰之后的效果是什么?
//接口
public final interface DemoInterface {}
//Illegal modifier for the interface DemoInterface; only public & abstract are permitted
//IDE会报错并提示你接口被非常的修饰符所修饰,接口只允许被public 和 abstract修饰
//抽象类
public final abstract class AbstractDemo {}
//The class AbstractDemo can be either abstract or final, not both
//IDE会报错并提示你类只能在abstract和final两个修饰符间选择其中一个来修饰类
//所以abstract和final是两个水火不相容的修饰符
  • final类中的所有成员方法都会被隐式地指定为final方法。

修饰方法


final修饰符可以用来修饰方法,被final所修饰的方法称为final方法,final方法和普通的方法在功能上一致,只是final方法不允许被子类所重写。final方法要比非final方法执行速度要快,因为在编译时已经静态绑定了,不需要在运行时进行动态绑定。
特性:

  • final方法不允许被子类所重写(意味着将方法锁住,不允许其他的继承类对其原有设计进行修改,且永远不需要修改)
  • final所修饰的方法将同意编译器在编译期间将该方法转换为内联函数(jdk7以前,之后会根据具体情况来决定该方法是否为内联函数),调用处展开,提高运行速度,但是会增加空间开销,是一种以空间换时间的方式
public Class Demo {
    public final show () {} 
    public say(){}
}

Class SonofDemo {
    @Override
    public final show (){ System.out.println("show method");} //error:overriden method is final
    public say(){System.out.println("say method");} 
}

延伸:

  • 如果方法可以被final所修饰,那么构造方法可以给final所修饰吗?效果是?

public class Demo {
    public final Demo() {}
    //Illegal modifier for the constructor in type Demo; only public, protected & private are permitted
    //IDE会报错并提示你构造方法只能被public,protected,private三种修饰符所修饰
}
  • private所修饰的方法会被隐式的指定为final方法

修饰变量


无论是成员变量还是局部变量,只要被final所修饰的变量则可以称为final变量,在Java中,只要被变量被final所修饰,就可以当做
是一个常量,是只可读的,JVM也会其做相应的优化。

特性:

  • final所修饰的变量的值不允许改变,只能是初始化时的值,不能再进行第二次赋值操作。这里有两种情况,就是变量分为基本类型和引用类型。
    ① final基本类型变量:基本类型变量被final修饰之后,变量的值将永远不得改变,在编译时,编译器会将被final所修饰的变量用它的直接量去代进出现它的计算表达式中。
    ② final引用类型变量:引用类型变量存储的是所指向对象的内存地址,是对象的引用,所以这里的不可变,指的是变量所指向的地址不可变,而所指向的对象实际是可以扩展的。
    //源代码
    public Class Test {
        final int a = 5;
        final int b = 6;
        {System.out.println(a + b);}
    }
    //反编译得到的代码
    public Class Test{
        final int a = 5;
        final int b = 6;
        {System.out.println(11)}
    }
    //计算表达式中的编译期常量在编译时会被它们的值替换,并且直接计算出结果
public class Demo {

     final static List list = new ArrayList();
     final static int a = 1;
     final static int b = 2;
     final static int c = 3;

     public static void main(String[] args) {
        //Demo.list = new ArrayList<>();    //error,引用变量不能再改变所执行的内存地址
        //Demo.a = b;                       //error,基本类型变量不能再改变所存储的值

        //list引用变量所执行的对象任然是可变的,只是list这个变量所存储的地址,不再发生改变
        //既不能再指向其他对象的地址
        Demo.list.add(a);                   
        Demo.list.remove(0);

    }
}
  • final所修饰的变量(成员变量,局部变量)必须显式初始化,不然是会报错的。
    ① 第一种方法是在声明的时候初始化
    ② 第二种方式是通过构造函数来初始化,赋予默认值。
public class Demo{
    //member variable
    final int a = 1;
    final int b;

    //constructor
    public Demo {
        this.b = 2;
    }

    public void show () {
        //local variable
        final int c =2;
    }
}


被final关键字修饰的一些好处


  • final关键字提高了性能,JVM和JAVA应用都会缓存final变量
  • final关键字可以安全的在多线程环境下进行共享,而不需要额外的同步开销
  • 使用final关键字,JVM会对变量,类和方法进行一些优化

final关键字总结

  • final关键字可以用于修饰变量,方法,和类
  • final成员变量不会隐式初始化,必须在声明时初始化或在构造器中初始化
  • final所修饰的局部变量可以先声明暂不赋值,随后再赋值,但只能赋值一次。如果只声明而没有被赋值,在编译期间,是会被编译器删除的。
  • 没有声明初始化的final成员变量称为空白final变量(blank final variable),他们必须在构造器中初始化。
  • 不能对final变量再次赋值,要区分final修饰的基本类型变量和引用类型变量的区别
  • 在匿名类中的所有变量都是final
  • final方法不能够进行重写,final不能用于修饰构造方法
  • final方法在编译阶段就已经绑定,称为静态绑定(static binding)
  • final类不能够被继承,所以final不能修饰接口和抽象类,因为抽象类必须被继承才有意义,所以final和abstract是死对头,绝对不能允许同时修饰一个类或一个方法。
  • final关键字不同于finally关键字,后者用于异常处理
  • final关键字与finalize()方法不同,后者是用于在object类定义的方法,是在垃圾回收之前被虚拟机调用的方法
  • 将类,方法,变量声明为final可以提高性能,JVM会对被final修饰的类,方法,变量进行优化



参考网址:

[InportNew] - 深入理解Java中的final关键字
[百度知道] - Java中final修饰的类有什么作用
在此感谢参考过的网址和博客的作者,谢谢!!

扫描二维码关注公众号,回复: 949798 查看本文章


上一节总结的内容 -【Java修饰符笔记之一】Java中Default关键字的两种使用方法



个人GitHub链接,欢迎赏脸

猜你喜欢

转载自blog.csdn.net/SnailMann/article/details/80252095