文章目录
前言
对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