黑馬程序員——面向對象(繼承、抽象、接口)

------- android培訓java培訓、期待與您交流! ----------

第一講    繼承

一、概述

        繼承是面向對象的一個重要特徵。當多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行爲,只要繼那個類即可。這時,多個類可以稱爲子類,單獨的這個類稱爲父類或者超類。例如:貓和豹子都是貓科動物,那麼就可以說描述貓這個對象創建的類,是子類;而描述貓科動物這個對象創建的類,就是父類。

        這樣類與類之間就存在了繼承的關係。子類可以直接訪問父類中的非私有的屬性和行爲。在代碼中通過extends關鍵字表示繼承關係。例:

            class Sonextends Father{}  //這也是在代碼中的書寫格式。

注意:千萬不要爲了獲取其他類中的功能,簡化代碼而繼承。必須是類與類之間有所屬關係纔可以繼承。這種所屬關係的表示爲is a

 

二、特點

        1、提高了代碼的複用性。

        2、讓類與類之間產生了關係。有了這個關係,提供了多態的前提。

注:Java語言中,只支持單繼承,不支持多繼承。例:一個兒子只能有一個父親。

       原因:因爲類與類多繼承的話,容易帶來安全隱患。如:當多個父類中定義了相同功能,當功能內容不同時,子類對象不確定要運行哪個一個。

        但是Java保留了這種機制,並用另一種體現形式來完成。叫多實現。

 

三、繼承的應用

        Java類中雖然不支持多繼承,但可以多層繼承。也就是一個繼承體系。如兒子繼承父親,父親繼承爺爺等。用代碼體現就是:

           class A{}

           class B extendsA{}

           class C extendsB{}

      那麼如何使用一個繼承體系中的功能呢?

      想要使用體系,先查體系中父類的描述,因爲父類中定義的是該體系中的共性功能。通過了解共性功能,就可以知道該體系的基本功能。這樣這個體系就可以基本使用了。

      在具體調用時,要創建最子類的對象。原因:

      一是因爲有可能父類不能創建對象。

      二是創建子類對象可以使用更多的功能,包括基本的也包括特有的。

 簡單一句就是:查閱父類功能,創建子類對象使用功能。

在此,先看一個示例程序:

[java] view plaincopy
  1. //定義一個人父類  
  2. class Person  
  3. {  
  4.     //名字和年齡是人的共有屬性  
  5.     String name;  
  6.     int age;  
  7.       
  8.     //在構造函數中對名字和年齡進行初始化  
  9.     Person(String name,int age)  
  10.     {  
  11.         this.name=name;  
  12.         this.age=age;  
  13.         System.out.println(name+"  "+age);  
  14.     }  
  15.     //人都具有睡覺的功能  
  16.     void sleep()  
  17.     {  
  18.         System.out.println("sleep");  
  19.     }  
  20. }  
  21. //定義一個學生,繼承人,作爲子類  
  22. class Student extends Person  
  23. {  
  24.     Student(String name,int age)  
  25.     {  
  26.         super(name,age);    //super關鍵字表示父類,因爲姓名和年齡在父類中進行了初始化動作,在這裏可以直接調用  
  27.     }  
  28.     //學生具有特有的功能,學習  
  29.     void study()  
  30.     {  
  31.         System.out.println("study");  
  32.     }  
  33.   
  34. }  
  35.   
  36. class Demo  
  37. {  
  38.     public static void main(String[] args)  
  39.     {  
  40.         Student s=new Student("zhangsan",20);  
  41.         System.out.println(s.name="wangwu");  
  42.         s.sleep();  
  43.         s.study();  
  44.     }  
  45. }  


子父類出現後,類成員的特點:

        類成員:變量,函數,構造函數。

1、變量

       如果子類中出現非私有的同名成員變量時,子類要訪問本類中的變量,用this。子類要訪問父類中的同名變量,用super

        super的使用和this的使用幾乎一致,且兩者都存在於方法區中。

              this表示本來對象的引用。    

              super表示父類對象的引用。

2、函數——覆蓋

       當子類出現和父類一模一樣的函數時,當子類對象調用該函數,會運行子類函數的內容。如同父類的函數被覆蓋一樣。這種情況是函數的另一個特性:重寫(覆蓋)。

       當子類繼承父類,沿襲了父類的功能,到子類中。但是子類雖具備該功能,但是功能的內容卻和父類不一致,這時,沒有必要定義新功能,而是使用覆蓋特性,保留父類的功能定義,並重寫功能內容。子類同時具有父類方法中的內容時,可以用super.方法();

       如在上面的示例程序中,如果Studentsleep()功能內容不相同,就可以在本類中,進行重寫,而創建對象進行調用時,打印的會是複寫之後的內容。

Student類中複寫:

[java] view plaincopy
  1. void sleep()  
  2.     {  
  3.         System.out.println("Student_sleep");  
  4.     }  

主函數中s.sleep();的結果就爲:

       

  注:1、子類覆蓋父類,必須保證子類權限大於等於父類權限,纔可以覆蓋,否則編譯失敗。

         2、靜態只能覆蓋靜態。

         3、父類中的私有方法不能被重寫。

小知識點:

       重載:只看同名函數的參數列表。

       重寫:子父類方法要一模一樣。

 

3、構造函數。

       在對子類對象進行初始化時,父類的構造函數也會運行。那是因爲子類的每一個構造函數默認第一行有一條隱式的語句super();

        super():會訪問父類中空參數的構造函數。而且子類中所有的構造函數默認第一行都是super();

       爲什麼子類一定要訪問父類中的構造函數。

        因爲父類中的數據子類可以直接獲取,所以子類對象在建立時,需要先查看父類是如何對這些數據進行初始化的。所以子類在對象初始化時,要先訪問一下父類中的構造函數。

       如果要訪問父類中指定的構造函數,可以通過手動定義super語句的方式來指定。在上面的示例中已經有了很好的體現。

       注:super語句一定定義在子類構造函數中的第一行。

構造函數結論:

       子類的所有構造函數,默認都會訪問父類中空參數的構造函數。因爲子類每一個構造函數內的第一行都有一句隱式super();當父類中沒有空參數的構造函數時,子類必須手動通過supe語句或者this語句形式來指定要訪問的構造函數。當然子類的構造函數第一行也可以手動指定this語句來訪問本類中的構造函數。子類中至少會有一個構造函數會訪問父類中的構造函數。

小知識點:

爲什麼this()和super()不能在同一個構造函數中?

       因爲它兩不能在同一行。

爲什麼不能再同一行?

       因爲初始化動作要先做。在子類構造函數中必有一個thi語句或者super語句。

知識點:final關鍵字

       繼承的出現,打破了對象的封裝性,使得子類可以隨意複寫父類中的功能。這也是繼承的一大弊端。那麼怎麼解決這個問題呢?這裏就引出了一個新的關鍵字——final(最終)。

        final作爲一個修飾符。具有以下特點:

        1、可以修飾類、函數、變量。

        2、被final修飾的類不可以被繼承。這樣就可以避免被繼承、被子類複寫功能。

        3、被final修飾的方法不可以被複寫。

        4、被final修飾的變量是一個常量只能賦值一次,既可以修飾成員變量,又可以修飾局部變量。

       當在描述事物時,一些數據的出現值是固定的,那麼這時爲了增強閱讀性,都給這些值起個名字。方便於閱讀。而這個值不需要改變,所以加上final修飾。作爲常量:常量的書寫規範所有字母都大寫,如果由多個單詞組成,單詞間通過_連接。

        5、內部類定義在類中的局部位置上時,只能訪問該局部被final修飾的局部變量。

 

第二講     抽象類

一、抽象的定義

        抽象就是從多個事物中將共性的,本質的內容抽取出來。

        例如:狼和狗共性都是犬科,犬科就是抽象出來的概念。

 

二、抽象類

         Java中可以定義沒有方法體的方法,該方法的具體實現由子類完成,該方法稱爲抽象方法,包含抽象方法的類就是抽象類。

        抽象類的由來:

        多個對象都具備相同的功能,但是功能具體內容有所不同,那麼在抽取過程中,只抽取了功能定義,並未抽取功能主體,那麼只有功能聲明,沒有功能主體的方法稱爲抽象方法。

        例如:狼和狗都有吼叫的方法,可是吼叫內容是不一樣的。所以抽象出來的犬科雖然有吼叫功能,但是並不明確吼叫的細節。

 

三、抽象類的特點

        1、抽象類和抽象方法必須用abstract關鍵字來修飾。

        2、抽象方法只有方法聲明,沒有方法體,定義在抽象類中。

        格式:修飾符abstract返回值類型  函數名(參數列表);

        3、 抽象類不可以被實例化,也就是不可以用new創建對象。原因如下:

        抽象類是具體事物抽取出來的,本身是不具體的,沒有對應的實例。例如:犬科是一個抽象的概念,真正存在的是狼和狗。

        而且抽象類即使創建了對象,調用抽象方法也沒有意義。

        4、抽象類通過其子類實例化,而子類需要覆蓋掉抽象類中所有的抽象方法後纔可以創建對象,否則該子類也是抽象類。

注:抽象類中可以有非抽象的方法。

下面通過一個實例,來說明抽象類的使用:

[java] view plaincopy
  1. /* 
  2. 假如我們在開發一個系統時需要對員工進行建模,員工包含 3 個屬性: 
  3. 姓名、工號以及工資。經理也是員工,除了含有員工的屬性外,另爲還有一個 
  4. 獎金屬性。請使用繼承的思想設計出員工類和經理類。要求類中提供必要的方 
  5. 法進行屬性訪問。 
  6.  
  7. 員工類:name id pay 
  8.  
  9. 經理類:繼承了員工,並有自己特有的bonus。 
  10.  
  11. */  
  12.   
  13. //員工類,也是父類  
  14. abstract class Employee  
  15. {  
  16.     private String name;//姓名  
  17.     private String id;  //工號  
  18.     private double pay;  //工資  
  19.       
  20.     //自定義構造函數初始化  
  21.     Employee(String name,String id,double pay)  
  22.     {  
  23.         this.name = name;  
  24.         this.id = id;  
  25.         this.pay = pay;  
  26.     }  
  27.       
  28.     public abstract void work();//抽象的工作方法  
  29.   
  30. }  
  31.   
  32. //經理類,繼承員工類  
  33. class Manager extends Employee  
  34. {  
  35.     private int bonus;//特有的獎金屬性  
  36.     Manager(String name,String id,double pay,int bonus)//子類的構造方法  
  37.     {  
  38.         super(name,id,pay);//調用超類中的構造器  
  39.         this.bonus = bonus;  
  40.     }  
  41.     public void work()//經理類的工作方法內容  
  42.     {  
  43.         System.out.println("manager work");  
  44.     }  
  45. }  
  46.   
  47. //普通員工類,繼承員工類  
  48. class Pro extends Employee  
  49. {  
  50.     Pro(String name,String id,double pay)  
  51.     {  
  52.         super(name,id,pay);  
  53.     }  
  54.     public void work()//普通員工類的工作方法內容  
  55.     {  
  56.         System.out.println("pro work");  
  57.     }  
  58. }  
  59.   
  60. class  AbstractDemo   
  61. {  
  62.     public static void main(String[] args)   
  63.     {  
  64.         new Manager("manager","001",10000,2000).work();  
  65.         new Pro("pro","020",5000).work();  
  66.     }  
  67. }  

 

四、抽象類與一般類的區別

        1、抽象類和一般類沒有太大的不同。該如何描述事物,還是如何描述事物。只不過,該事物中出現了一些不知道具體內容的方法部分。這些不確定的部分,也是該事物的功能,需要明確出來,但是無法定義主體。通過抽象方法來表示。

        2、抽象類比一般類多了個抽象函數。就是在類中可以定義抽象方法。

        3、抽象類不可以實例化。

        4、抽象類雖然不能創建對象,但是也有構造函數。供子類實例化調用。

注:1、被abstract修飾的函數不能同時被privatefinalstatic修飾。

      原因:

                final:被final修飾的類不能有子類。而被abstract修飾的類一定是一個父類。

                private:抽象類中的私有的抽象方法,不被子類所知,就無法被複寫。

                           而抽象方法出現的就是需要被複寫。

                static:如果static可以修飾抽象方法,那麼連對象都省了,直接類名調用就可以了。

                            可是抽象方法運行沒意義。

        2、抽象有一個特殊的地方:抽象類中可以不定義抽象方法。這樣做可以不讓本來實例化,也可以用於模塊設計。

如下面的小程序:

[java] view plaincopy
  1. /* 
  2. 需求:獲取一段程序的運行時間 
  3. 原理:將程序開始執行到執行結束的時間相減就是程序的運行時間了 
  4. 思路:1、由於想要獲取的程序時未知的,可以將其抽象出去,通過子類繼承複寫的方式獲得程序 
  5.       2、利用java中提供的當前時間功能記錄下程序開始執行和執行結束的時間,然後相減 
  6. */  
  7. abstract class  GetTime  
  8. {  
  9.     public final void getTime()//加final表示不能被複寫  
  10.     {  
  11.         long start=System.currentTimeMillis();//開始執行時間  
  12.         program();  
  13.         long end=System.currentTimeMillis();//執行結束時間  
  14.         System.out.println("毫秒"+(end-start));  
  15.     }  
  16.     abstract void program();//由於程序不確定,故抽象出去  
  17. }  
  18.   
  19. //要獲取執行時間的程序  
  20. class GetProgram extends GetTime  
  21. {  
  22.     void program()  
  23.     {  
  24.         for(int x=0;x<1000;x++)  
  25.             System.out.print(x+" ");  
  26.     }  
  27. }  
  28. class TemplateDemo  
  29. {  
  30.     public static void main(String[] args)   
  31.     {  
  32.         new GetProgram().getTime();  
  33. //      System.out.println("Hello World!");  
  34.     }  
  35. }  

 

第三講     接口

一、概述

       接口,可以被認爲是一個特殊的抽象類。當抽象類中的方法都是抽象的,那麼該類可以通過接口的形式來表示。接口使用interface來表示,子類中用implements實現。格式爲:

         interface 接口名{}   

        子類名 implements接口名{}

格式特點:

        1、接口中常見定義:常量,抽象方法。

        2、接口中的成員都有固定修飾符。

               常量:public static final

               方法:public abstract

        3、接口中的成員都是public的。

在使用中,常量可以不寫publicstatic final,方法可以不寫publicabstract,編譯時Java會自動添加這些修飾符,因爲這是固定的格式修飾符。但爲了方便閱讀,通常我們都寫上。

 

二、特點

        1、接口是對外暴露的規則。

        2、接口是程序的功能擴展。

        3、接口的出現降低耦合性。

        4、接口可以用來多實現。這也是對多繼承不支持的轉換形式。java支持多實現。

        5、類與接口之間是實現關係,而且類可以繼承一個類的同時實現多個接口。

        6、 接口與接口之間可以有繼承關係。而且可以多繼承。

注意:

1、接口不可以創建對象的,因爲有抽象方法。需要被子類實現(implements),子類對接口中的抽象方法全都覆蓋後,子類纔可以實例化。否則子類是一個抽象類。

        2、實現多個接口時,接口中不可以有返回不同類型的同名抽象函數。這樣子類實現時將不能複寫。

 

三、接口與抽象類

       共性:都是不斷向上抽取出來的抽象的概念。

       區別:

                1、抽象類體現繼承關係,一個類只能單繼承。

                    接口體現實現關係,一個類可以多實現。同時接口與接口之間有繼承關係。

                2、抽象類是繼承,是 "is a "關係。

                    接口是實現,是 "like a"關係。

                3、抽象類中可以定義非抽象方法,供子類直接使用。

                    接口的方法都是抽象,接口中的成員都有固定修飾符。

                4、抽象類中可以私有變量或方法。

                    接口中的常量和方法都是public修飾的權限。

接口實例小程序:

[java] view plaincopy
  1. //抽象學生類  
  2. abstract class Student  
  3. {     
  4.     //抽象的學習方法  
  5.     abstract void study();  
  6.     //共性內容非抽象的睡覺方法  
  7.     void sleep()  
  8.     {  
  9.         System.out.println("sleep");  
  10.     }  
  11. }  
  12.   
  13. //接口,吸菸  
  14. interface Smoking  
  15. {  
  16.     void smoke();  
  17. }  
  18.   
  19. //Zhangsan這個對象繼承學生類,實現吸菸接口  
  20. class Zhangsan extends Student implements Smoking  
  21. {  
  22.     //複寫學習方法  
  23.     void study()  
  24.     {  
  25.         System.out.println("Zhangsan_study");  
  26.     }  
  27.   
  28.     //複寫吸菸方法  
  29.     public void smoke()  
  30.     {  
  31.         System.out.println("Zhangsan_smoking");  
  32.     }  
  33. }  
  34.   
  35. //Lisi是好學生,不吸菸  
  36. class Lisi extends Student   
  37. {     
  38.     //複寫學習方法  
  39.     void study()  
  40.     {  
  41.         System.out.println("Lisi_study");  
  42.     }  
  43. }  
  44.   
  45.   
  46. class InterfaceDemo  
  47. {  
  48.     public static void main(String[] args)   
  49.     {  
  50.         Zhangsan z = new Zhangsan();  
  51.         z.study();  
  52.         z.smoke();  
  53.         new Lisi().study();  
  54.     }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章