1. 程式人生 > >菜雞的Java課筆記 第二十 方法的覆寫

菜雞的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哪個類)
    觀察呼叫的方法是否已經被該子類覆寫,如果覆寫則呼叫被覆寫的方法,如果沒有覆寫則呼叫從父類繼承而來的方法