java的final关键字

前言

对final关键字的作用不了解,看了几篇文章后,大致有了了解,整理下来一起学习吧

一、final的含义

final表示 最后的,最终的含义。一旦赋值,不能重新被赋值。

二、final方法的使用

修饰类

  • 格式:

    final class 类名{}

  • 使用场景:

    不希望类被继承时

  • 使用原因:

    被final修饰的类,是不允许被继承的,可以认为该类很完美。
    不能被继承,自然也就不能被修改和扩展了。

  • 其他备注:

    1、一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写(因为没有子类)
    2、在类中,final关键字和abstract关键字不能同时使用,因为矛盾。(abstract方法被被继承时,必须要重新,final是必须不能重写)

修饰方法

  • 格式:

    修饰符 final 返回值类型 方法名(参数列表){ // 方法体}

  • 使用场景:

    不希望子类重写父类的某个方法(不能重写,但是可以继承和使用)

  • 其他备注:

    1、被final修饰的方法,也认为该方法很完美,而且也不允许继承类重写该方法。
    2、重写被final修饰的方法时会报错
    3、方法用final来修饰也有一定的性能提升上的帮助,因为jvm直到它不会被覆盖重写,所以可以以更简单的方法来处理
    4、private的方法默认都会被编译器加上final
    5、方法中,final关键字和abstract关键字也不能同时使用,理由同上

修饰变量

  • 格式:

    final 类型 变量名;

  • 说明:

    1、被final修饰的变量,表示该属性一旦被初始化便不可以被修改了。即只能赋值一次
    2、变量赋值:可以在声明变量时直接初始化;也可以声明时不赋值,后续使用时赋值。
    3、修饰的变量如果是基本类型,那么变量值不可以被修改
    4、修饰的变量是引用类型,final只保证这个引用变量所引用的地址不会改变,即一直引用同一个对象,但可以改变引用变量所引用的对象的内容,如 final User user = new User();,user就不能再指向其他对象或者null了

    	@Data
    	@NoArgsConstructor
    	@AllArgsConstructor
    	class Student{
    	    private String name;
    	    private Integer age;
    	}
    
    	// 
    	final Student student = new Student("hello",12);
    	student.setAge(12); // student被final修饰了,但是依然可以设置age
    	student = new Student(); // 这里就会报错哦
    

修饰参数

  • 被final修饰的参数,该参数在整个方法内都不允许被修改

三、final变量的“宏替换”

  • 如果一个final变量满足三个条件,这个final变量就不再是一个变量,相当于一个直接量
  • 使用final修饰符修饰
  • 定义该final变量时指定了初始值
  • 初始值在编译时就被确定下来了
    	// str1为宏变量,直接指向了常量池中的“final666”
        final String str1 = "final"+666;
        System.out.println(str1=="final666");   // 结果为true
    
        // str2需要调用String方法,没办法不符合二三条,所以不为宏变量
        final String str2 = "final"+String.valueOf(666);
        System.out.println(str2=="final666");   // 结果为false
    
        // s2在编译的时候也被确定了值
        String s1="final测试";
        String s2 = "final"+"测试";
        System.out.println(s1==s2);   // 结果为true
    
        // st1和st2都是宏变量,可以执行宏替换,所以编译的时候可以确定s3的值
        final String st1 = "final";
        final String st2 = "测试";
        String s3 = st1+st2;
        System.out.println(s3==s1);   // 结果为true
    
        // s4的值是由st3和st4计算后得到,无法在编译时确定值
        String st3 = "final";
        String st4 = "测试";
        String s4 = st3+st4;
        System.out.println(s4==s1);   // 结果为false
    

四、java中哪些类是被final修饰的(目的是供我们使用,不让我们改变)

  • 修饰的方法:object 的getClass() 方法
  • 类:String Math Scanner
  • string类:public final class String
  • public final class Math
  • public final class Scanner

五、匿名内部类使用外部变量时为何要强制使用final修饰

  • java对闭包支持不够完整
  • java内部类与外部持有的是值相同的不同的变量。

    扩展:
    那么,有没有想过为什么?而像其他支持完整闭包的语言如JavaScript,Python等,是没有这等限制的。究其原因,是Java对闭包支持不够完整,或者说它并不是像动态语言那样的完整闭包。对于匿名内部类来说,编译器会创建一个命名类(OutClass$1之类的),然后把匿名类所在的能捕获的变量,以构造参数的形式传递给内部类使用,这样一样,外部的变量与内部类看到的变量是不同的,虽然它们的值是相同的,因此,如果再允许外部修改这些变量,或者内部类里面修改这些变量,都会造成数据的不一致性(因为它们是不同的变量),所以Java强制要求匿名内部类访问的外部变量要加上final来修饰。对于其他语言,匿名内部类,持有的是外部变量的一个包装的引用(wrapper reference),这可以能看不懂,但是理解起来就是内部类能直接访问外部变量,外部与闭包内部访问的是同一个变量,因此外部修改了,内部能看到变化,内部修改了,外部也能看到变化。

六、为什么能加final的就建议多用,除非不能用呢?

  • 域变量尽可能加:多线程条件下会有很大优势,可以省去构造时的多线程同步。因为域变量(也可以称为共享变量) 是不可变的,会减少同步上的麻烦
  • 类和方法能提升性能:正常的类和方法,为了继承和方法重写,jvm需要做准备。如果加上了final,jvm可以做一些优化,提升一下性能
  • final变量能提升可读性:因为不能修改了

七、总结,final的使用细节

  • final修饰的属性一般称之为常量
  • final修饰的属性在定义时,必须赋初始值,并且之后不能再修改。如user
  • final修饰的属性是静态的,初始化位置要么是定义时,要么是在静态代码块中,但是不能在构造器中赋值。
  • final修饰的类不能继承,但是可以进行实例化
  • 如果类不是final修饰的,但是含有final方法,那么方法不能被重写,但是类可以继承
  • 如果类已经被final修饰了,内部的方法就没必要用final了
  • final和static搭配使用效率更高,因为这样不会导致类加载

参考文档:
(偷偷的说,这几篇文章看完,就会了解好多细节哦)
https://www.jb51.net/article/274429.htm
https://www.jb51.net/article/265028.htm
https://www.jb51.net/program/287574iq4.htm
https://www.jb51.net/program/292196dr2.htm
https://www.jb51.net/program/310556woz.htm
https://blog.csdn.net/wwwwwww31311/article/details/113174133

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值