官术网_书友最值得收藏!

3.2 類的繼承性

繼承性是面向對象語言的又一個基本特性,它是一種由已有的類創建新類的機制,正是因為有這種機制,才使得面向對象語言編寫的程序代碼具有較高的復用性。

3.2.1 類的繼承

繼承是指相關的類之間的層次關系。利用繼承,可以先創建一個共有屬性的一般類,根據該一般類再創建具有特殊屬性的新類,新類繼承一般類的狀態和行為,并根據需要增加它自己的新的狀態和行為。

由繼承而得到的類稱為子類,被繼承的類稱為父類。類繼承的具體定義格式如下。

    class subclassname extends superclassname{
    …
    }

在上述類的聲明中,通過使用關鍵字extends來創建一個類的子類,其中,subclassname是聲明的子類的類名,superclassname是繼承的父類的類名。

在3.1.1小節中介紹過Java類的聲明,在當時定義的類并沒有使用extends關鍵字,那么是不是表示當時定義的類沒有繼承其他的類呢?答案是否定的。在Java語言中,Object類是所有類的祖先類,也就是說所有的類都是直接或者間接繼承Object類的。所以當沒有使用extends關鍵字時,就表示這個類只是Object類的子類。

說明

與C++語言中的繼承不同,Java語言不支持多重繼承,子類只能有一個父類。

【實例3-7】實現類的繼承。

首先定義父類Student。

    01  class Student {
    02      int stu_id;              //父類的成員變量
    03      void set_id(int id) {   //父類的成員方法
    04          stu_id=id;
    05      }
    06      void show_id() {         //父類的成員方法
    07          System.out.println(“The student_ID is:”+stu_id);
    08      }
    09  }

【代碼說明】該類中第2行定義一個int型的成員變量,第3行和第6行分別定義名稱為set_id和show_id()的兩個成員方法。

然后定義繼承Student類的子類Granduate類。

    01  class Granduate extends Student {
    02      int dep_number;              //子類的成員變量
    03      void set_dep(int dep_num) {   //子類的成員方法
    04             dep_number=dep_num;
    05      }
    06      void show_dep() {             //子類的成員方法
    07             System.out.println(“The department number is:”+dep_number);
    08      }
    09  }

【代碼說明】該類是Student類的子類,因此,它可以直接使用Student類中定義的成員變量和成員方法,而無須重復定義。除此之外,在第2行還定義了自己的成員變量dep_number,在第3行和第6行分別定義了成員方法set_dep()和show_dep()。

最后定義調用Granduate類的應用程序類。

    01  public class Student_Show {
    02        public static void main(String args[]) {
    03             Granduate sun=new Granduate();          //創建子類對象
    04             sun.set_id(102);                        //調用父類中定義的方法
    05             sun.set_dep(6);                         //調用子類中定義的方法
    06             sun.show_id();                          //調用父類中定義的方法
    07             sun.show_dep();                         //調用子類中定義的方法
    08         }
    09  }

【代碼說明】在應用程序類中的第3行創建了Granduate類,第4行和第6行分別調用其父類中定義的成員方法,第5行和第7行則分別調用子類中定義的成員方法。

【運行結果】該程序的輸出結果如圖3.3所示。

圖3.3 程序運行結果

說明

根據類的繼承關系,創建的子類對象一定也是父類的對象。例如上例中創建的Granduate類的對象sun也是其父類Student類的對象,但是反過來,父類的對象則不一定是子類的對象。

3.2.2 方法的重載和覆蓋

當類之間出現繼承關系之后,在子類中就將可能出現成員方法的重載和覆蓋。這是面向對象編程中多態性的體現。

1.方法的覆蓋

如果在子類中定義了與父類中的成員方法同名的成員方法,那么當子類的對象在程序中調用該成員方法時,調用的將是子類中新定義的成員方法,而子類中繼承下來的父類中的成員方法就將被覆蓋掉了,如果要訪問被覆蓋的成員方法,則只有通過父類的對象來調用它了。

例如,在實例3-7中子類Granduate中定義的成員方法與其繼承的父類中的成員方法沒有同名,所以不存在方法的覆蓋。下面修改Granduate類的定義,具體代碼如下:

    01  class Granduate extends Student {
    02      int dep_number;
    03      void set_dep(int dep_num) {
    04             dep_number=dep_num;
    05      }
    06      //定義與父類中成員方法同名的方法,實現方法的覆蓋
    07      void show_id() {
    08             System.out.println(“The department number is:”+dep_number);
    09      }
    10  }

【代碼說明】 子類Granduate中的第7行,定義了一個與父類Student中成員方法同名的方法,這就是方法的覆蓋。

然后將調用Granduate類的應用程序類的代碼修改如下:

    01  public class Student_Show {
    02        public static void main(String args[]) {
    03             Granduate sun=new Granduate();
    04             sun.set_id(102);
    05             sun.set_dep(6);
    06             //由于方法覆蓋,這里調用的將是子類中定義的show_id()方法
    07             sun.show_id();
    08             }
    09  }

圖3.4 調用子類中覆蓋后的方法

【代碼說明】在應用程序的第7 行通過子類實例調用了show_id()方法,由于在子類和父類中都定義了該方法,那么通過子類調用時將調用子類中定義的show_id()方法。

【運行結果】執行應用程序時,將調用子類中定義的show_id()方法,最終程序輸出結果如圖3.4所示。

2.方法的重載

如果在一個類中,定義了兩個或者兩個以上的具有不同參數列表的同名方法,這種情況就被稱為方法的重載,方法的重載體現了Java作為面向對象語言的多態性。

那么什么是不同的參數列表呢?僅僅是形參名稱不同的兩個參數列表實際上仍然是相同的,但如果是參數的個數或者參數的數據類型不同,則這樣的參數列表才是不同的。因此,同一個對象在調用具有相同名稱的方法時,會根據傳遞進來的參數的個數或數據類型的不同,而自動選擇對應的方法。

在類的繼承關系中,如果當子類中定義了與父類中同名的方法時,但是方法的參數列表不同,這時在子類中將對該方法進行重載,即子類中既繼承下來父類的方法,又定義了自己的新的成員方法,不會對父類的方法進行覆蓋。

下面修改實例3-7中的Granduate類的定義,具體代碼如下:

    01  class Granduate extends Student {
    02      int dep_number;
    03      void set_dep(int dep_num) {
    04             dep_number=dep_num;
    05      }
    06      //定義與父類中成員方法同名的方法,但參數列表不同
    07      void show_id(String name) {
    08             System.out.println(“The department number of”+name+” is:”+dep_number);
    09      }
    10  }

【代碼說明】在該類中的第7行定義了與父類中成員方法同名的方法,但是與父類中的show_id()方法的參數列表不同,因此實際上在Granduate類中將存在兩個名稱為show_id的成員方法,但是這兩個方法一個是參數為空,一個是具有一個字符串類型參數。

然后將調用Granduate類的應用程序類的代碼修改如下:

    01  public class Student_Show {
    02        public static void main(String args[]) {
    03             Granduate sun=new Granduate();
    04             sun.set_id(102);
    05             sun.set_dep(6);
    06             //由于方法重載,這里調用子類中的兩個不同的show_id()方法
    07             sun.show_id();
    08             sun.show_id(“sun”);
    09             }
    10  }

【代碼說明】在應用程序的第7 行和第8 行分別兩次調用了show_id()方法,但是這兩次調用的方法的參數不同,第7行將調用父類Student中定義的show_id()方法,第8行將調用子類Granduate中定義的show_id()方法。

【運行結果】執行應用程序時,將調用子類中重載的兩個不同的show_id()方法,最終程序輸出結果如圖3.5所示。

圖3.5 調用重載的方法

3.2.3 抽象類和最終類

在一般情況下,Java中的所有的類都可以被其他類繼承,也可以直接被實例化使用。但是有兩種特殊的類,一種是專門用來給其他類做父類的,自己不能夠被實例化,另一種是不能夠再被其他類所繼承的。這就是本小節要詳細介紹的抽象類和最終類。

1.抽象類

面向對象的編程思想使得開發者可以編寫模塊化的程序,然后用類似搭積木的方式來組織這些模塊以實現特定的功能。甚至可以對一個未定的功能預留一個模塊的位置,留待以后去實現。

將這種思想應用于類的定義中,對于某種未定的操作,可以在類中先只定義方法聲明,不定義方法實現,以后再在這個類的子類中去具體實現這個方法。這樣的方法被稱為抽象方法,而包含抽象方法的類就被稱為抽象類。

抽象方法和抽象類的定義方式都是在方法名和類名之前加上abstract關鍵字。其中,抽象方法的聲明與普通方法基本一致,也需要有方法名、參數列表和返回值類型,只是沒有方法體。類的成員方法的聲明格式如下:

    [<修飾符>] abstract <返回類型> <方法名> ([<參數列表>]);

說明

在參數列表的括號后面一定要加上分號。

抽象類由于包含抽象方法,因此它不能使用new關鍵字進行實例化,也不能在類中定義構造函數和靜態方法,但是抽象類中可以包含具體實現了的非靜態方法。所以讀者不要誤解成抽象類中的方法全部都是抽象方法,而是只有一個類中包含一個抽象方法,那么這個類就是抽象類。抽象類的子類中應該對抽象方法進行具體的實現,否則子類本身也就成為抽象類了。

【實例3-8】抽象類的定義和使用。

首先定義抽象類Student,該類中包含一個抽象方法show_id()。

    01  abstract class Student {
    02      int stu_id;
    03      void set_id(int id) {
    04          stu_id=id;
    05      }
    06      //定義抽象方法
    07      abstract void show_id();
    08  }

【代碼說明】在該抽象類的第7行定義了一個抽象方法show_id()。

然后定義繼承Student類的子類Granduate類。

    01  class Granduate extends Student {
    02      int dep_number;
    03      void set_dep(int dep_num) {
    04             dep_number=dep_num;
    05      }
    06      //具體定義父類中的抽象方法
    07      void show_id() {
    08             System.out.println(“The department number is:”+dep_number);
    09      }
    10  }

【代碼說明】在該類的第7行定義了父類中的抽象方法show_id()的具體實現。

說明

必須具體定義父類中的抽象方法,否則該類也將成為抽象類。

最后定義調用Granduate類的應用程序類。

    01  public class Student_Show {
    02        public static void main(String args[]) {
    03             Granduate sun=new Granduate();//創建子類的實例
    04             sun.set_id(102);
    05             sun.set_dep(6);
    06             sun.show_id();//調用子類中已經實現了的父類中的抽象方法
    07             }
    08  }

【代碼說明】在應用程序類的第6行調用show_id()方法,由于該方法已經在Granduate類中被實現,所以可以被正確調用。

【運行結果】執行應用程序,將調用子類中具體定義后的show_id()方法,最終程序輸出結果與如圖3.4所示的結果一樣。

2.最終類

如果在一個類定義前加上final關鍵字,那么這個類就不能再被其他的類所繼承,這樣的類被稱做最終類。最終類可以避免開發者編寫的類被別人繼承后加以修改。

例如,下面的類定義和繼承:

    final class A {
          …..
    }
    class B extends A {
          ….
    }

這樣的繼承將是錯誤的,在程序編譯時將提示類A是不能被繼承的。

final關鍵字除了可以用在聲明最終類時,還可以應用在成員變量和成員方法的聲明上,如果在成員變量的定義前加上final關鍵字,則這個變量的值在以后的程序中只能被引用,而不能被改變,final在這里的作用相當于C++語言中的const。

說明

使用final的成員變量必須在聲明時同時給定初始值。

例如,聲明不能被修改的成員變量的示例代碼如下:

    class A {
          final float PI=3.14159f;
          final float E=2.71828f;
          ….
    }

如果在成員方法定義前加上final關鍵字,那么表示這個方法在子類中不能被覆蓋。

主站蜘蛛池模板: 斗六市| 汝城县| 石楼县| 温泉县| 宝应县| 新兴县| 阳春市| 开鲁县| 平原县| 华池县| 高唐县| 万载县| 凌云县| 宝鸡市| 沙河市| 赤城县| 富宁县| 台江县| 澎湖县| 吉首市| 河东区| 体育| 天柱县| 涡阳县| 贵定县| 昆山市| 贵定县| 宣化县| 鄱阳县| 乡城县| 昂仁县| 衢州市| 仪陇县| 双柏县| 岳西县| 嘉禾县| 深州市| 田阳县| 台北县| 镇赉县| 通榆县|