final是最终的意思,它是一个关键字也是一个修饰符
它可以修饰 数据、方法、类
1.final修饰数据
final修饰的是基本数据类型的时候,就是最终值不能发生改变(final修饰的数据可以先声明,再去赋值,只能赋值一次)
如果成员变量被final修饰且没有给值,那么要保证在创建变量之前赋值 (构造方法或者构造代码块 ,多个构造方法重载的时候,每个重载构造方法都要给声明的成员变量赋值),如果被static 和final 共同修饰
的时候,要在类加载完成之前完成赋值 (静态代码块)
final int i=2; //i=4;//语句错误,final修饰变量的数据不能改变---最终值 final int j; //final修饰的数据可以先声明,再去赋值,只能赋值一次 j=6;
final修饰引用数据类型
final修饰引用数据类型,最终值就是引用的地址,地址值不能改变
final int[] arr= {1,2,3}; //元素值赋值,这个时候数组中的值是可以改变,那么final修饰的就不是数组元素的值 arr[2]=6; arr[0]=5; //arr=new int[5];//此语句错误,地址值发生改变。 //arr.length=5;//此语句错误,数组长度也是最终值。
final修饰成员变量的值
在创建对象前就要赋值(构造方法和构造代码块任选其一且只能赋值一次)
class A{ final int i; { i=4; //构造代码块中赋值 } public A() { //i=5; //构造代码块和构造函数赋值两者取其一 } }
static 和final共同修饰(最终静态):在类加载之前就要赋值且只要赋值一次
class A{ static final int i; static { i=4; } { } public A() { } }
2.final修饰方法
final 修饰方法那么这个方法可以重载和重写吗
可以重载
方法可以被继承但是不能重写
class A{ //重载 public final void m() {} public final void m(int i) {} } class B extends A{ //注解判断是否可以重载 @Override //public final void m() {} //重写报错了 }
《Java编程思想》中讲到final方法时提到,使用final方法原因有两个,
一、锁定方法。防止任何继承类修改、覆盖
二、效率。在java早期实现中,如果将一个方法指明为final,就是同意编译器将针对该方法的调用都转化为内嵌调用。…..
大概就是,如果是内嵌调用,虚拟机不再执行正常的方法调用(参数压栈,跳转到方法处执行,再调回,处理栈参数,处理返回值),而是直接将方法展开,以方法体重的实际代码替代原来的方法调用。这样减少了方法调用的开销。当然如果一个方法体本身就很大,这样的优势就小了很多了。
引用:函数/方法调用过程中CPU要进行现场处理(不妨看做是一种中断),当前的变量状态、寄存器状态、程序计数器PC。。。都要一一入栈保护起来,调用返回时又要一一出栈恢复以继续执行。相对于顺序执行流程,函数调用的入栈出栈带来了额外的开销,效率没有顺序执行高。
在最近的java设计中,虚拟机(特别是hotspot技术)可以自己去根据具体情况自动优化选择是否进行内联,因此和final关键字就无关了。
内联函数:
在计算机科学中,内联函数(有时称作在线函数或编译时期展开函数)是一种编程语言结构,用来建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展);也就是说建议编译器将指定的函数体插入并取代每一处调用该函数的地方(上下文),从而节省了每次调用函数带来的额外时间开支。
但在选择使用内联函数时,必须在程序占用空间和程序执行效率之间进行权衡,因为过多的比较复杂的函数进行内联扩展将带来很大的存储资源开支。另外还需要非常注意的是对递归函数的内联扩展可能带来部分编译器的无穷编译。
C、C++中可以声明内联函数,在java中不支持直接声明,但是jvm会根据情况进行优化内联。
内联函数特点:
(1)提升效率。如上说明。
(2)占更多内存空间。编译器直接将内联函数扩展开,调用多复制品就多,因此更占用内存。
(3)java中不需额外关注,jvm会自动进行优化
内联举例:
1
2
|
int max ( int a, int b){ if (a > b) return a; else return b;} void main() { ..... a = max (x, y); // 内联,等价于 "a = (x > y ? x : y);" 直接扩展开了,不再调用方法 ..... }
|
3.final修饰类
final修饰的类不能被继承,但是可以继承别的类
final class A{ //属性 String name; //方法 public void m() {} //无参构造 public A() { } } /*class B extends A{ //不能继承最终类A }*/