final數據只能夠在定義時初始化,或者是在聲明blank final後在構造函數中初始化。對於基本類型,final域值不可變,對於引用類型,
final的引用指向不可變,可是其引用所指向的對象的屬性實際上是可變的。
final 數據能夠被繼承的,而且能夠被子類同名屬性覆蓋,參看示例:安全
public class SuperAttribute { public final String str = "父類的final屬性"; public final String strNotHide = "父類的final屬性 沒有被隱藏的 能夠被子類繼承的"; } public class SubAttribute extends SuperAttribute { public final String str = "子類的final屬性"; @Test public void test() throws Exception { //父類引用指向子類對象 屬性是不存在多態性的 SuperAttribute supera = new SubAttribute(); System.out.println(supera.str);//輸出 父類的final屬性 SubAttribute sub= new SubAttribute(); System.out.println(sub.str);//輸出 子類的final屬性 System.out.println(sub.strNotHide);//父類的final屬性 沒有被隱藏的 而且這個final屬性是能夠繼承的 } }
Java容許在參數列表中以聲明的方式將參數指明爲final。這樣就沒法在方法中更改參數引用所指向的對象。這一特性主要用來向匿名內部類傳遞數據。ide
如今使用final方法的緣由只有一個:把方法鎖定,以防止任何繼承類修改他的含義,想要確保繼承中使方法行爲保持不變,
而且不會覆蓋。記住,final方法的含義只有一個:方法不可被子類改變(重寫override和覆蓋隱藏hiding)函數
對於實例方法final的含義爲:在子類中不能夠重寫這個方法
對於靜態方法final的含義爲: 在子類中不能夠隱藏(覆蓋)這個方法
示例代碼以下:this
public class SuperFinalMethod { public final void finalMethod(){ System.out.println("父類的final方法"); } public static void staticFinalMethod(){ System.out.println("父類的static final方法"); } public static final void staticFinalMethodNotHide(){ System.out.println("父類的static final方法 沒有覆蓋"); } public static void main(String[] args) { } } public class SubFinalMethod extends SuperFinalMethod{ /** * Cannot override the final method from SuperFinalMethod * 實例final方法是不能夠被override(重寫)的,方法簽名一致就不能夠 public final void finalMethod(){ System.out.println("父類的final方法"); } */ /** * 實例final方法雖然不能夠被重寫,可是在子類中能夠重載這個final方法 */ public final void finalMethod(int i){ finalMethod();//從父類中繼承了 System.out.println("父類的final方法"); } //隱藏(覆蓋)父類的靜態方法 public static void staticFinalMethod(){ System.out.println("子類的static final方法"); } /** * <b>不能夠經過編譯</b> * * 編譯器給出的提示信息: * SubFinalMethod 中的 staticFinalMethodNotHide() 沒法覆蓋 SuperFinalMethod 中的 * staticFinalMethodNotHide();被覆蓋的方法爲 static final * *Eclipse給出的提示信息是錯誤的:Cannot override the final method from SuperFinalMethod *staticFinalMethodNotHide()方法是靜態的,不能夠重寫(),只能覆蓋,可是又因爲staticFinalMethodNotHide()方法是 *final的,因此也沒法覆蓋。 * *因此final對於實例方法和靜態方法的含義是不一樣的 *對於靜態方法final的含義是不可覆蓋(不可隱藏 can't hiding) *對於實例方法final的含義是不可重寫override *總之final方法含義就是子類繼承的這個方法不可變(不可重寫,不可隱藏覆蓋) public static final void staticFinalMethodNotHide(){ System.out.println("父類的static final 方法是沒法覆蓋的"); } */ }
類中全部的private方法都隱式的指定爲final的。因爲沒法取用private方法,因此也就沒法覆蓋它。(private方法在繼承類中
是沒法使用的,天然也就沒有覆蓋之說了)
可是下面的情形可能會引發一些疑惑。設計
class WithFinals { // Identical to "private" alone: private final void f() { System.out.println("WithFinals.f()"); } // Also automatically "final": private void g() { System.out.println("WithFinals.g()"); } } class OverridingPrivate extends WithFinals { private final void f() { System.out.println("OverridingPrivate.f()"); } private void g() { System.out.println("OverridingPrivate.g()"); } } class OverridingPrivate2 extends OverridingPrivate { public final void f() { System.out.println("OverridingPrivate2.f()"); } public void g() { System.out.println("OverridingPrivate2.g()"); } } public class FinalOverridingIllusion { private static Test monitor = new Test(); public static void main(String[] args) { OverridingPrivate2 op2 = new OverridingPrivate2(); op2.f(); op2.g(); // You can upcast: OverridingPrivate op = op2; // But you can't call the methods: //! op.f(); //! op.g(); // Same here: WithFinals wf = op2; //! wf.f(); //! wf.g(); monitor.expect(new String[] { "OverridingPrivate2.f()", "OverridingPrivate2.g()" }); } } ///:~
"覆蓋"只有在某方法是基類的接口的一部分時纔會出現。即,必須能將一個對象向上轉型爲它的基本類型並調用相同的方法。
若是某個方法爲private,它就不是基類接口的一部分。若是在導出類中以相同的名稱生成一個public,protected,defualt
方法,則只是生成了一個新的方法。與是否覆蓋並無關係。
另外,對於覆蓋,必須方法簽名一致纔是覆蓋,若是方法簽名不一致,好比方法參數不一樣,也存在覆蓋。以下所示:code
public class FinalObj { void defaultFinalMethod(String str) { System.out.println(" defaultFinalMethod " + str); } public final void protectedfinalMethod(String str) { System.out.println(" FinalObj protected final " + str); } public void protectedMethod(String str) { System.out.println(" FinalObj protected " + str); } } public class FinalObjSub extends FinalObj { @Override public void protectedMethod(String str) { System.out.println(" FinalObjSub protected " + str); } /** @Override 沒法經過編譯,由於父類中不存在這個方法,也沒有覆蓋之說 public void protectedMethod(int str) { System.out.println(" FinalObj protected " + str); } */ }
當將某個類總體定義爲final時,就代表你不打算繼承該類,並且也不容許別人這麼作。換句話說,你對該類的設計用不須要
作出任何變更,或者是出於安全考慮,你不但願它有子類。對象
靜態方法是能夠繼承的,可是在子類中即便能夠定義一個與父類方法簽名相同的方法會覆蓋掉父類的方法,可是這並非重寫
重寫應該體如今多態性上有所體現,可是覆蓋父類靜態方法並不會體現多態性。看看下面的實例代碼:繼承
public class SuperStaticObj { public final void finalMethod(){ System.out.println(" super finalMethod"); } public void method() {//普通實例方法 體現多態性,能夠由子類繼承並能夠重寫override System.out.println("fatherMethod"); } //靜態方法,不體現多態性,能夠由子類繼承,可是不能夠重寫(orverride),只能夠覆蓋 public static void staticMethod() { System.out.println("fatherStaticMethod"); } public static void staticMethodNotHide() { System.out.println("fatherStaticMethodNotHide"); } } public class SubStaticObj extends SuperStaticObj { @Override public void method() { System.out.println("SubMethod"); } /** *父類中也存在相同的方法簽名的staticMethod()方法,在子類中定義一個與父類相同方法簽名的 *靜態方法這種方式並非覆寫,而只是隱藏(覆蓋)了父類的靜態方法,若是是覆寫的話,那麼在父類引用指向 *子類對象時,對象會表現出多態性 *請參考test4Static()方法 */ public static void staticMethod() { System.out.println("SubStaticMethod"); } /** *能夠直接在子類中調用父類的靜態方法,說明父類的靜態方法是繼承了的 */ public static void staticMethodFromSuperType() { staticMethodNotHide(); } @Test public void test4Static() throws Exception { //父類引用指向子類對象 SuperStaticObj sso = new SubStaticObj(); sso.method();//輸出SubMethod 調用的運行時子類的方法 sso.staticMethod();/** 輸出 fatherStaticMethod 雖然父類引用指向的是子類對象,可是仍然調用的是父類的方法 **/ } /** * 在子類中直接調用被隱藏的父類的static方法,會調用這個類中的使父類方法隱藏的那個新方法 */ @Test public void test4StaticHide() throws Exception { staticMethod();//SubStaticMethod } }
屬性存在繼承性,可是卻不表現多態性,也就是說屬性能夠繼承不可重寫,能夠覆蓋
多態僅針對實例方法,與實例的屬性無關。重寫只對方法有效,對屬性無效!示例代碼:接口
public class SuperAttribute { public int i = 0; public int j = 0; public void printI(){ System.out.println(" 父類 i = " + i +" ,j = " +j); } } public class SubAttribute extends SuperAttribute { //覆蓋了父類的i屬性i = 0 public int i = 1; public void printI(){ System.out.println(" 子類 i = " + i +" ,j = " +j); } @Test public void test4AttributeCover() throws Exception { //對於屬性i 和 j存在繼承 super.printI();//i = 0 ,j = 0 printI();//i = 1 ,j = 0 //多態性的驗證 父類引用指向子類對象 SuperAttribute sa = new SubAttribute(); sa.printI();//子類 i = 1 ,j = 0 方法具備多態性 System.out.println("i = " + sa.i);//i=0屬性不具有多態性,所以也沒有重寫之說,只是覆蓋了父類的同名屬性 } }
假設子類從超類中繼承了一個方法,在這個方法中須要訪問一個屬性,即便這個屬性在子類中從新被覆蓋,那子類對象調用這個父類方法
時仍然訪問的是父類的屬性。除非在子類中重寫父類方法,這樣纔會訪問子類的屬性。示例以下:ip
public class SuperAttribute { public int i = 0; public int j = 0; public void printI(){ System.out.println(" 父類 i = " + this.i +" ,j = " +this.j); } public void printJ(){ System.out.println(" 父類 i = " + this.i +" ,j = " +this.j); } } public class SubAttribute extends SuperAttribute { //覆蓋了父類的i屬性i = 0 public int i = 1; public void printJ(){ System.out.println(" 子類 i = " + this.i +" ,j = " +this.j); } @Test public void test4AttributeCover() throws Exception { //父類引用指向子類對象 SuperAttribute sa = new SubAttribute(); sa.printI();// 父類 i = 0 ,j = 0 訪問的是父類的屬性 sa.printJ();//子類 i = 1 ,j = 0 override printJ()以後訪問的是子類的屬性 //子類引用指向子類對象 SubAttribute sub = new SubAttribute(); sub.printI();// 父類 i = 0 ,j = 0 訪問的是父類的屬性 sub.printJ();//子類 i = 1 ,j = 0 override printJ()以後訪問的是子類的屬性 } }
author by zhaob time : 2014-09-13 14:18