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修饰的类有什么作用
在此感谢参考过的网址和博客的作者,谢谢!!
上一节总结的内容 -【Java修饰符笔记之一】Java中Default关键字的两种使用方法