工作久了,一些基础知识时间长不用就忘了。实际工作中我们一般用final来修饰静态常量是不可变的,那final修饰Map会如何呢?String为什么是不可变的,因为String类是final修饰的,不能被继承,那还有其他原因么?关于final的其他用法久而久之就忘了。
Final的基础用法
- 修饰变量。
- 用final修饰的变量,只能进行一次赋值操作,并且在生存期内不可以改变它的值。final修饰的变量可以先声明,后赋值
- final修饰基本类型时,起到常量的作用 ,基本类型的值不可变。final修饰引用类型时,不能指向其他的对象,但被引用的对象的值可以改变。
- 当final作用于类的成员变量时,成员变量(局部变量只需要保证在使用之前被初始化赋值即可)必须在定义时或者构造器中进行初始化赋值
- 在匿名类中所有变量都必须是final变量
- 修饰方法参数
编写方法时,可以在参数前面添加final关键字,它表示在整个方法中,不会(实际上是不能)改变参数的值,具体类似于修饰数据。即不能改变参数的值,但是可以改变引用类型参数对象的值。同时,即时没有final修饰,参数的改变也不会影响到方法外的变量 - 修饰方法
- final修饰方法不能被覆盖(重写)。
- final修饰的方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。
- 修饰类
final修饰的类无法被继承。且final类中的所有成员方法都会被隐式地指定诶final方法
1.final修饰的类
可以看到被final修饰的类被继承编译器报错了,如果去掉final就好了
那么问题来了,为什么设计了继承还要有final来破坏这种继承关系呢?
在Java编程思想中这样解释:使用final方法的原因有两个。第一个原因是把方法锁定,以防止任何继承类修改它的含义;第二个原因是效率,在早期的java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的java版本中,不需要使用final方法进行这些优化了。
2.final修饰变量
public class TestFinal {
public static void main(String[] args) {
String a = "xiaomeng2";
final String b = "xiaomeng";
String d = "xiaomeng";
String c = b + 2;
String e = d + 2;
System.out.println((a == c));
System.out.println((a == e));
}
}
这段代码的输出结果是什么呢?
true false
原因:
- 变量a指的是字符串常量池中的xiaoming2
- 变量b是final修饰的,变量b的值在编译时候就已经确定了它的值,换句话说就是提前知道了变量b的内容是个啥,相当于一个编译器常量
- 变量c是b+2得到的,由于b是一个常量,所以在使用b的时候相当于使用b的原始值来进行计算,所以c生成的也是一个常量,a是常量,c也是常量,都是xiaoming2而jva中常量池中只能生成一个唯一的xiaoming2的字符串,所以a和c是相等的
- d指向常量池中xiaomign,但由于d不是final修饰,也就是说在使用d的时候不会提前知道d的值是什么,所以在计算e的时候就不一样了,e的话使用的是d的引用计算,变量d的访问却需要在运行时通过链接来进行,所以这种计算会在堆上生成xiaoming2,所以最终e指向的是堆上的xiaoming2,所以a和e是不相等的。
总结:a和e是常量池的xiaoming2,e是堆上的xiaoming2
final修饰引用变量和基本变量
基本变量
final修饰基本变量后,就不可改变了
引用变量
可以看出,final修饰了Test1后,不能重新给他指向新的引用地址,但是Test1里的成员变量却是可以改变的。
final的好处
- final方法比非final快一些 final关键字提高了性能。
- JVM和java应用都会缓存final变量
- final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销
- 使用final关键字,JVM会对方法、变量及类进行优化