学习java的时候常常会被修饰符搞糊涂,这里总结下static final和final的区别。
1、static 强调只有一份,final 说明是一个常量,final定义的基本类型的值是不可改变的,但是fianl定义的引用对象的值是可以改变的,下面举个例子来说明:
package DifStaticFinalAndFinal; class SelfCounter { private static int counter; private int id=counter++; public String toString(){ return "SelfCounter: "+id; } }
package DifStaticFinalAndFinal; class WithFinalFields { static final SelfCounter wffs=new SelfCounter(); final SelfCounter wff=new SelfCounter(); public String toString(){ return "wff= "+wff+",\n wffs= "+wffs; } }
主函数:
package DifStaticFinalAndFinal; public class StaticFinal { public static void main(String[] args) { System.out.println("First Object:"); System.out.println(new WithFinalFields()); System.out.println("Second Object:"); System.out.println(new WithFinalFields()); } }
运行结果:
First Object: wff= SelfCounter: 1, wffs= SelfCounter: 0 Second Object: wff= SelfCounter: 2, wffs= SelfCounter: 0
分析为什么wff两次的运行结果不同,而wffs两次的运行结果相同?
因为wffs这个容器是用static final来定义的,static 强调只有一份,因此只有一个值,
而final修饰的引用是可以变化的,因此wff的值是可以变化的,这也是final修饰基本类型和引用的不同。
2、在方法中将参数指明为final时,在使用该方法时,可以读参数但是无法使用该参数。
package cn.qdu.chapter7_example; public class FinalArguments { void with(final Gizmo g){ } void without(Gizmo g){ g=new Gizmo(); g.spin(); } int g(final int i){return i+1;} public static void main(String[] args) { FinalArguments bf=new FinalArguments(); bf.with(null);//不管这里的参数换成什么,都是执行void(final Gizmo g)方法,无法更改参数 bf.without(null); } }
3、为什么使用final方法呢?
原因有两个。其一是把方法锁定,确保在继承中使用方法行为不变,并且不会被覆盖;
其二是效率,如果一个方法指明为final,就是同意编译器将针对该方法的所有调用都转为内嵌调用。 转为内嵌调用的目的是节省开销,因为编译器发现一个final方法调用命令时,会跳过程序代码这种正常方式而执行方法调用机制(将参数压入栈,跳至方法代码处并执行,然后跳回并清理栈中的参数,处理返回值),并且以方法体中的实际代码的副本来替代方法调用。但是如果一个方法很大,程序很膨胀,就会看不到内嵌带来的任何性能的提高。
4、final和private关键字
类中所有private方法都隐式地指定为是final的,因为private关键字只能被本类调用,其他类中的方法也无法覆盖private修饰的方法,因此和加上final效果是一样的。
5、当某个类的整体定义为final时,表明该类不能被继承,方法不能被覆盖,且final类中的所有方法都隐式指定为是final的,方法声明为final后还可以有效地“关闭”动态绑定。
6、static加载类的动作只发生一次。
最后,说了这么多,也要对final做一个客观的评价。若方法或类不想让别人来继承和修改,设定为final是明智的,但是在团体中这样会阻碍其他程序员通过你想不到的合理的途径来复用类,这样的话final方法就显得过于严苛了。