菜雞的Java課筆記 第二十 方法的覆寫
1.方法的覆寫
當子類定義了與父類中的完全一樣的方法時(方法名稱,引數型別以及個數,返回值型別)這樣的操作就稱為方法的覆寫
範例:觀察方法的覆寫
class A{ public void print(){ System.out.println("******************"); } } class B extendsa A{ } } public class inherit{ public static void main(String args[]){ B b= new B(); b.print(); } } /* 結果: ****************** */
此時B是A的子類,並且B類中沒有定義任何的方法。此時B類將直接繼承A類中的println()方法執行
範例:發生覆寫
class A{ public void print(){ System.out.println("******************"); } } class B extendsa A{ public void print(){ //方法名稱一樣 System.out.println("!!!!!!!!!!!!!!!!!!"); } } public class inherit{ public static void main(String args[]){ B b= new B(); b.print(); } } /* 結果: !!!!!!!!!!!!!!!!!! */
...
class A{ public void print(){ System.out.println("******************"); } }class B extendsa A{ public void print(){ // 與父類的方法完全一樣 System.out.println("!!!!!!!!!!!!!!!!!!"); } } class C extendsa A{ public void print(){ System.out.println("¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥"); } public class inherit{ public static void main(String args[]){ C c = new C(); c.print(); } } /* 結果: ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ */
(主要是看 new 誰)
此時的程式之中使用了B類進行物件的例項化操作,並且在B類中已經明確的覆寫了A類中的print()方法
那麼最終所呼叫的一定就是被覆寫過的方法
範例:分析方法覆寫的含義
class Person{ private String name; private int age; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } public String getlnfo(){ return "姓名:"+this.name +",年齡:"+this.age; } } class Student extends Person{ // Student 是Person 的子類 private String school; // 子類自己擴充的屬性 public void setSchool(String school){ this.school = school; } public String getSchool(){ return this.school; } } public class inherit{ public static void main(String args[]){ Student stu = new Student();// 例項化子類物件 stu.setName("少爺");//通過Person類繼承而來 stu.setAge(20);//通過Person類繼承而來 stu.setSchool("清華");//子類自己擴充的屬性 System.out.println(stu.getlnfo()); } } /* 結果: (問題:少了School 這個值) 姓名:少爺,年齡:20 */
******************************************
class Person{ private String name; private int age; public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } public String getlnfo(){ return "姓名:"+this.name +",年齡:"+this.age; } } class Student extends Person{ // Student 是Person 的子類 private String school; // 子類自己擴充的屬性 public void setSchool(String school){ this.school = school; } public String getSchool(){ return this.school; } public String getlnfo(){ // 保留方法名稱,但是有需要對功能進行擴充 return super.getlnfo() +"學校:"+this.school; // return "姓名:"+super.getName() +",年齡:"+super.getAge() +"學校:"+this.school; } public class inherit{ public static void main(String args[]){ Student stu = new Student();// 例項化子類物件 stu.setName("少爺");//通過Person類繼承而來 stu.setAge(20);//通過Person類繼承而來 stu.setSchool("清華");//子類自己擴充的屬性 System.out.println(stu.getlnfo()); } }
實質上所謂的方法覆寫原因:
父類中定義的方法名稱是其他程式所認可的名稱,屬於使用的習慣
但是子類在使用的過程之中,發現原始的方法不能夠支援自己的操作,而且又需要保留豬方法名稱,這樣才出現了覆寫的概念
並且通過以上的分析可以發現一點:
this.方法():會先找本類中是否有指定的方法,如果本類沒有則使用父類繼承而來的方法
super.方法():不查詢本類的方法,而直接找父類的方法
但是覆寫本身也是有嚴格要求的:被覆寫的方法不能夠擁有比父類更為嚴格的訪問控制權限。
對於訪問的控制權限嚴格來講一共有四個,已經學習過三個:private<default(friend)<public
按照以上的思路,如果說現在父類中的方法使用了public訪問許可權宣告,那麼子類只能夠使用public 而如果父類使用了default訪問許可權宣告,那麼子類可以使用public或default
範例:錯誤的覆寫
class A{ public void print(){ System.out.println("******************"); } } class B extendsa A{ void print(){ // 此時的方法訪問許可權嚴格 System.out.println("!!!!!!!!!!!!!!!!!!"); } } public class inherit{ public static void main(String args[]){ B b= new B(); b.print(); } } /* 結果:出錯 */
但是此時又會出現這樣一種情況,如果父類中的方法使用了private呢?那麼子類覆寫方法時如果使用了default也屬於許可權擴大這樣可以覆寫嗎?
範例:正常覆寫
class A{ public void fun(){ this.print(); } public void print(){ System.out.println("******************"); } } class B extendsa A{ public void print(){ System.out.println("!!!!!!!!!!!!!!!!!!"); } } public class inherit{ public static void main(String args[]){ B b= new B(); b.fun(); } } /* 結果: !!!!!!!!!!!!!!!!!! */
下面將父類中的println()方法許可權修改為private
class A{ public void fun(){ this.print(); } private void print(){ System.out.println("******************"); } } class B extendsa A{ public void print(){ System.out.println("!!!!!!!!!!!!!!!!!!"); } } public class inherit{ public static void main(String args[]){ B b= new B(); b.fun(); } } /* 結果: ****************** */
從許可權的角度來看此時應該符合覆寫的要求
通過結果可以發現,此時子類並沒有進行方法的覆寫所以就可以得出結論:
父類中private宣告的方法不能夠被子類所覆寫,而且最重要的是這樣的操作幾乎沒有意義
在實際之中對於方法的定義,95%的情況下都只會使用public宣告
在進行方法覆寫之後都會存在有一個就近取用的關係,如果面對本類方法自己呼叫自己的情況,因為預設情況下呼叫本類方法時都會採用“this.方法()” 的形式處理
而在使用this呼叫結構的時候,會首先找到本類如果本類找不到的操作再去查詢父類
為了可以不查詢本類而直接找到父類,建議使用“ super.方法() ” 的形式呼叫
以後為了表示明確,強烈建議:子類訪問父類方法前都是 super
面試題:請解釋Overloading與Override的區別?在進行Overloading的時候能否返改變回值型別
區別 | 方法過載 | 方法覆寫 |
單詞 | Overloading | Override |
範圍 | 發生在一個類中 | 發生在繼承關係之中 |
定義 | 方法名稱相同,引數的型別以及個數不同 | 方法名稱相同,引數的型別以及個數,返回值全部相同 |
許可權 | 沒有許可權要求 | 被覆寫的方法不能擁有比父類更為嚴格的訪問控制權限 |
在進行方法過載的時候可以使用不同的返回值型別,但是從設計的標準來講不建議使用
2.屬性的覆蓋
當子類定義了與父類屬性名稱相同的屬性時,就稱為屬性的覆蓋
範例:觀察屬性的覆蓋
class A{ String info = "mysterious"; } class B extendsa A{ int info = 100; // 名稱相同 public void print(){ System.out.println(this,info); System.out.println(super.info); } } public class inherit{ public static void main(String args[]){ B b= new B(); b.print(); } } /* 結果: 100 mysterious */
從實際開發的標準要求來講,類中的屬性必須使用private封裝,那麼一旦使用了private封裝屬性覆蓋沒有意義了
面試題:請解釋this與super的區別?
區別 | this | super |
概念 | 表示呼叫本類屬性(this.屬性),本類方法(this.方法,this()) | 呼叫父類屬性(super.屬性),父類方法(super.方法(),super()) |
構造要求 | 呼叫構造方法是必須放在構造方法的首行,所以this()與super()不能夠同時出現,但是子類永遠會去呼叫父類中的構造方法 | 呼叫構造方法是必須放在構造方法的首行,所以this()與super()不能夠同時出現,但是子類永遠會去呼叫父類中的構造方法 |
特殊要求 | 表示當前物件 |
使用this實際上會先從本類開始查詢所需要的內容,如果沒有去查詢父類,而如果使用的是super則表示不查詢本類直接查詢父類的定義
總結
1.所有類中的屬性都必須使用private定義,這樣一來覆蓋屬性就沒有任何意義了
2.方法的覆寫呼叫特點:
看例項化的是那個子類的物件(new 出現在哪裡或者說是new哪個類)
觀察呼叫的方法是否已經被該子類覆寫,如果覆寫則呼叫被覆寫的方法,如果沒有覆寫則呼叫從父類繼承而來的方法