final关键字


  final的含义为“不可改变的”,不想做改变通常有两种理由:设计或效率,下面谈论了可能使用到final的三种情况:域,方法和类

final域

将数据声明为final是因为需要一个:
  1. 一个永不改变的编译时常量
  2. 一个在运行时被初始化的值,而你不希望它被改变
在这里附上运行时/编译时的定义,了解可以跳过:
 Java的引用变量有两个类型,一个是编译时类型,一个是运行时类型,编译时类型由声明该变量时使用   的类型决定,运行时类型由实际赋给该变量的对象决定。 
Person p=new Women()(Women类继承自Person类)那么,假如p的属性修饰符为public 那么访问属性时得到 的是Person类的属性还是Women类的属性?方法调用又是哪个类? 
答案:会得到Person类的属性,调用  Women类的方法。为什么会这样呢?这里就需要知道什么是编译时类型和运行时类型,Java程序状态会分为编译和运行这两种状态,编译时,JVM会在栈中静态创建基本数据变量,和引用数据变量的引用。回到刚刚那句代码,显然,p这个引用就是在编译时创建的。那么,p的编译时类型就是Person了,当运行这句java代码时,JVM在堆中为p新建一块内存,对应new Women()这句代码,所以p的运行时类型就是Women
编译时常量存在什么样的风险? 
编译时常量,在使用时会被直接写成值,而不会再从原来的类中读取。这样就会导致问题的产生:如果   A类定义了常量,B类使用了常量,并且都进行了编译。当A类的源码被改动了,常量的值发生了变化。我们对A类进行了重新编译,但是没有对B类进行重新编译;那么B类中用到的是原来A类中的常量值,即旧值。这就导致了风险的发生。
 对于编译时常量(static final修饰,根据惯例编译时常量用大写表示,并使用下划线分隔各个单词)这种情况,编译器可以将常量带入任何可能用到它的计算式中,在编译时执行计算式,这减轻了一些运行时负担。在Java中,这类常量必须是基本数据类型,再对其定义的同时必须进行赋值。编译时常量只占据一个一段不能改变的储存空间。

而对 对象引用使用final时,引用指向恒定不变,然而对象自身却是可以被修改的(可以使用单例模式以取得对象恒定不变的效果单例模式可以使类只生成一个对象),这一效果同样适用于数组,String,它们也是对象。

  • 空白final 
定义:所谓空白final是指 被声明为final但又未给定初值的域

优势:使一个类中的final域就可以做到根据对象有所不同,却又保持其恒定不变的特性

例子:
public class BlankFinal{
    private final int i;//空白final
    BlankFinal(int x){
        i = x;
    }
}
必须在域的定义处或者每个构造器中用表达式对final进行赋值

  • final参数 
Java允许在参数列表以声明的方式将参数指明为final,你可以读参数,却无法修改参数,这一特性主要用来向匿名内部类传递数据。

#final域与多线程

我们可以通过将一个域声明为final来安全的访问一个共享域,因为final字段是不可变更的,所以不需要担心操作的原子性问题,而线程会在构造函数完成之后才看到这个字段,这保证了final变量值的一致性


final方法

  • 使用final方法的原因有三个
  1. 第一个原因是把方法锁定,以防任何继承类修改它的含义(也就是说无法覆盖final方法,但可以重载),这是出于设计的考虑:想要确保在继承中使方法行为保持不变,并且不会被覆盖。
  2. 第二个原因是效率问题(现在JVM和编译器会解决这个问题,不再需要也不建议使用final方法进行优化) ,当编译器发现final方法的调用命令时,将直接内嵌代码,这节省了调用的开销(final方法代码量很大这种情况不适用)。
  3. 有效的关闭“动态绑定”,然而大多数情况下,这样做的对程序的整体性能不会有什么改观。所以,最好根据设计来决定是否使用final,而不是出于试图提高性能的目的来使用final
#关于动态绑定
动态绑定又称后期绑定或运行时绑定,在Java中动态绑定是默认行为,除了static方法、final方法和private方法(实际上它就是final方法)之外,其它所有方法都是动态绑定,Think in Java的作者Bruce Eckel认为后期绑定就是多态,“不要犯傻,如果它不是后期绑定,它就不是多态。”通过这句话可以看出他对多态的理解。

#关于对多态的理解
我曾经比较认同的一种说法是 后期绑定是运行时多态,而重载则是编译时多态,不过看起来Bruce Eckel本人并不认同这种说法,我们应该以辩证的态度对待这两种说法,关于两种态度的分析,之后有机会我会单独写一篇博文,也欢迎大家就这个问题进行探讨。
  • final和private关键字
类中所有private方法都隐式地指定为final,也就是说,它们都是不可覆盖的。


final类

当将某个类整体定义为final时,就表明了你不打算继承这个类,并且类中的所有方法都隐式的被指定为final的。

总结

本文只作学习交流之用,转载请注明出处。
https://danserlesgens.blogspot.com/2018/03/final.html

Comments

Popular posts from this blog

抓包工具Wireshark下载及安装教程

HTTP协议特性

Java中Synchronized的用法