根据上下文环境,Java的关键字final的含义存在着细微的区别,但通常它指的是"这是无法改变的."不想做改变可能出于两种原因:设计或效率.由于这两个原因相差很远,所以final有可能误用
以下谈到了final的三种情况:数据.方法和类
一.final数据
恒定不变的数据比如
1.一个永不改变的编译时常量 //java中这类常量必须是基本数据类型
2.一个在运行时时被初始化的值,而你不希望它被改变.
3.当对对象使用final时,不变的只是指向对象的引用无法被改变,而对象自身可以被修改
package object; import java.util.*; import static net.mindview.util.Print.*; class Value{ int i ;//Package access public Value(int i){ this.i = i;} } public class FinalData{ private static Random rand = new Random(47); private String id; public FinalData(String id){ this.id = id;} //Can be fianl int valueOne = 9 private final int valueOne = 9; private static final int VALUE_TWO = 99;// 根据惯例既是static又是final的域将用大写表示 public static final int VAL_THREE = 39; //public 说明可以被用于包外,定义为static,才强调只有一份,定义为final,则说明它是一个常量 private final int i4 = rand.nextInt(20); static final int INT_5 = rand.nextInt(20); private Value v1 = new Value(11); private final Value v2 = new Value(33); private static final Value VAL_3 = new Value(33); //Arrays: private final int []a = {1,2,3,4,5,6}; public String toString() { return id + ": " + "i4 = " + i4 + ", INT_5= " + INT_5; } public static void main(String[] args) { FinalData fd1 = new FinalData("fd1"); //! fd1.valueOne++;; // Error: can't change value fd1.v2.i++; //object isn't constant fd1.v1 = new Value(9); //ok -- no final for(int i = 0; i < fd1.a.length; i++) fd1.a[i]++;//Object isn't constant //! fd1.v2 = new Value(0); //Error: can't //! fd1.VAL_3 = new Value(1 ;//Change reference //! fd1.a = new int[3]; print(fd1); print("Creading new FinalData"); FinalData fd2 = new FinalData("fd2"); print(fd1); print(fd2); } } /* output: * fd1: i4 = 15, INT_5= 18 *Creading new FinalData *fd1: i4 = 15, INT_5= 18 *fd2: i4 = 13, INT_5= 18 *///:~
二:空白final
java 允许生产"空白final",所谓空白final是指被声明为final但又未给初值的域(field),无论什么情况,编译器都会确保空白final字使用前必须被初始化,但是,空白final在关键字final的使用上提供了很大的灵活性,为此,一个类中的final域就可以做到根据对象而有所不同,却又保持其恒定不变的特性
package object; class Poppet{ private int i; Poppet(int ii){i = ii;} } public class BlankFinal{ private final int i = 0; //Initialized final private final int j ; //blank final private final Poppet p; //Blank final reference //blank finals must be initialized in the constructor public BlankFinal(){ j = 1; //initialized p = new Poppet(1); } public BlankFinal(int x) { j = x; //initialized final p = new Poppet(x); //initialized final reference } public static void main(String[] args) { new BlankFinal(); new BlankFinal(47); } }//必须在域的定义出或每个构造器中用表达式对final赋值,这正是final域在使用前总是被初始化的原因所在
final 参数
java 允许参数列表中以声明的方式将参数指明为final,这意味着你无法再方法中改变参数所引用的对象
//: ch7_19/final.java // blank final package object; class Gizmo{ public void spin(){} } public class FinalArguments{ void with(final Gizmo g) { //! g = new Gizmo(); //Illegal --g is final } void without(Gizmo g) { g = new Gizmo(); //ok -- g not final g.spin(); } // void f(final int i) { i++;} //can't change // you can only read from a final primitive int g(final int i){return i+1;} public static void main(String[] args) { FinalArguments bf = new FinalArguments(); bf.without(null); bf.with(null); } }
三 final 方法
使用final 方法的原因有两个,第一个原因是把方法锁定,以防止任何继承类修改它的含义,这是出于设计的考虑:想要确保再继承中使方法行为保持不变,并且不会被覆盖
过去使用final方法的第二个原因是效率,现在不用了,只有再明确禁止导出类的方法覆盖基类方法时,才将基类方法设置为final
private和final:由于无法取得private方法,所以也就无法覆盖它,可以对private加final,但无意义
//: reusing/FinalOverridingIllusion.java // it only loos like you cna override // a private or private final method package ch7_20; class WithFinals{ //Identical to "private" alone private final void f(){ System.out.println("WithFinals.f()"); } private void g() { System.out.println("WithFinals.g()"); } } class OverridePrivate extends WithFinals{ private final void f() { System.out.println("Overridingprivate.f()"); } private void g() { System.out.println("Overridingprivate.g()"); } } class OverridePrivate2 extends OverridePrivate{ public final void f() { System.out.println("Overridingprivate2.f()"); //"覆盖" 只有在某方法时接口的一部分才会出现 } public void g() { System.out.println("Overridingprivate2.g()"); } } public class FinalOverridingIllusion{ public static void main(String[] args) { OverridePrivate2 op2 = new OverridePrivate2(); op2.f(); op2.g(); // you can upcast OverridePrivate op = op2; // but you can't call the methods //! op.f(); //! op.g(); WithFinals wf = op2; //! wf.f(); //! wf.g(); } }
final 类
当将某个类的整体定义为final时,就表明了 你不打算继承该类,而且也不允许别人这样做,
package object; class SmallBrain{ } final class Dinosaur{ int i = 7; //Dinosaur 所有方法都隐式的指定为是final的 int j = 1; SmallBrain x = new SmallBrain(); void f(){} } // class further extends dinosaur {} // error: annt extend final class Dinosaur public class Jurassic{ public static void main(String[] args) { Dinosaur n = new Dinosaur(); n.f(); n.i =40; n.j++; } }
在设计类时将方法指明时final,应该说时明智的.