------- android培訓、java培訓、期待與您交流! ----------
第一講 繼承
一、概述
繼承是面向對象的一個重要特徵。當多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行爲,只要繼那個類即可。這時,多個類可以稱爲子類,單獨的這個類稱爲父類或者超類。例如:貓和豹子都是貓科動物,那麼就可以說描述貓這個對象創建的類,是子類;而描述貓科動物這個對象創建的類,就是父類。
這樣類與類之間就存在了繼承的關係。子類可以直接訪問父類中的非私有的屬性和行爲。在代碼中通過extends關鍵字表示繼承關係。例:
class Sonextends Father{} //這也是在代碼中的書寫格式。
注意:千萬不要爲了獲取其他類中的功能,簡化代碼而繼承。必須是類與類之間有所屬關係纔可以繼承。這種所屬關係的表示爲is a。
二、特點
1、提高了代碼的複用性。
2、讓類與類之間產生了關係。有了這個關係,提供了多態的前提。
注:Java語言中,只支持單繼承,不支持多繼承。例:一個兒子只能有一個父親。
原因:因爲類與類多繼承的話,容易帶來安全隱患。如:當多個父類中定義了相同功能,當功能內容不同時,子類對象不確定要運行哪個一個。
但是Java保留了這種機制,並用另一種體現形式來完成。叫多實現。
三、繼承的應用
Java類中雖然不支持多繼承,但可以多層繼承。也就是一個繼承體系。如兒子繼承父親,父親繼承爺爺等。用代碼體現就是:
class A{}
class B extendsA{}
class C extendsB{}
那麼如何使用一個繼承體系中的功能呢?
想要使用體系,先查體系中父類的描述,因爲父類中定義的是該體系中的共性功能。通過了解共性功能,就可以知道該體系的基本功能。這樣這個體系就可以基本使用了。
在具體調用時,要創建最子類的對象。原因:
一是因爲有可能父類不能創建對象。
二是創建子類對象可以使用更多的功能,包括基本的也包括特有的。
簡單一句就是:查閱父類功能,創建子類對象使用功能。
在此,先看一個示例程序:
- //定義一個人父類
- class Person
- {
- //名字和年齡是人的共有屬性
- String name;
- int age;
- //在構造函數中對名字和年齡進行初始化
- Person(String name,int age)
- {
- this.name=name;
- this.age=age;
- System.out.println(name+" "+age);
- }
- //人都具有睡覺的功能
- void sleep()
- {
- System.out.println("sleep");
- }
- }
- //定義一個學生,繼承人,作爲子類
- class Student extends Person
- {
- Student(String name,int age)
- {
- super(name,age); //super關鍵字表示父類,因爲姓名和年齡在父類中進行了初始化動作,在這裏可以直接調用
- }
- //學生具有特有的功能,學習
- void study()
- {
- System.out.println("study");
- }
- }
- class Demo
- {
- public static void main(String[] args)
- {
- Student s=new Student("zhangsan",20);
- System.out.println(s.name="wangwu");
- s.sleep();
- s.study();
- }
- }
子父類出現後,類成員的特點:
類成員:變量,函數,構造函數。
1、變量
如果子類中出現非私有的同名成員變量時,子類要訪問本類中的變量,用this。子類要訪問父類中的同名變量,用super。
super的使用和this的使用幾乎一致,且兩者都存在於方法區中。
this表示本來對象的引用。
super表示父類對象的引用。
2、函數——覆蓋
當子類出現和父類一模一樣的函數時,當子類對象調用該函數,會運行子類函數的內容。如同父類的函數被覆蓋一樣。這種情況是函數的另一個特性:重寫(覆蓋)。
當子類繼承父類,沿襲了父類的功能,到子類中。但是子類雖具備該功能,但是功能的內容卻和父類不一致,這時,沒有必要定義新功能,而是使用覆蓋特性,保留父類的功能定義,並重寫功能內容。子類同時具有父類方法中的內容時,可以用super.方法();
如在上面的示例程序中,如果Student的sleep()功能內容不相同,就可以在本類中,進行重寫,而創建對象進行調用時,打印的會是複寫之後的內容。
在Student類中複寫:
- void sleep()
- {
- System.out.println("Student_sleep");
- }
主函數中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、抽象類通過其子類實例化,而子類需要覆蓋掉抽象類中所有的抽象方法後纔可以創建對象,否則該子類也是抽象類。
注:抽象類中可以有非抽象的方法。
下面通過一個實例,來說明抽象類的使用:
- /*
- 假如我們在開發一個系統時需要對員工進行建模,員工包含 3 個屬性:
- 姓名、工號以及工資。經理也是員工,除了含有員工的屬性外,另爲還有一個
- 獎金屬性。請使用繼承的思想設計出員工類和經理類。要求類中提供必要的方
- 法進行屬性訪問。
- 員工類:name id pay
- 經理類:繼承了員工,並有自己特有的bonus。
- */
- //員工類,也是父類
- abstract class Employee
- {
- private String name;//姓名
- private String id; //工號
- private double pay; //工資
- //自定義構造函數初始化
- Employee(String name,String id,double pay)
- {
- this.name = name;
- this.id = id;
- this.pay = pay;
- }
- public abstract void work();//抽象的工作方法
- }
- //經理類,繼承員工類
- class Manager extends Employee
- {
- private int bonus;//特有的獎金屬性
- Manager(String name,String id,double pay,int bonus)//子類的構造方法
- {
- super(name,id,pay);//調用超類中的構造器
- this.bonus = bonus;
- }
- public void work()//經理類的工作方法內容
- {
- System.out.println("manager work");
- }
- }
- //普通員工類,繼承員工類
- class Pro extends Employee
- {
- Pro(String name,String id,double pay)
- {
- super(name,id,pay);
- }
- public void work()//普通員工類的工作方法內容
- {
- System.out.println("pro work");
- }
- }
- class AbstractDemo
- {
- public static void main(String[] args)
- {
- new Manager("manager","001",10000,2000).work();
- new Pro("pro","020",5000).work();
- }
- }
四、抽象類與一般類的區別
1、抽象類和一般類沒有太大的不同。該如何描述事物,還是如何描述事物。只不過,該事物中出現了一些不知道具體內容的方法部分。這些不確定的部分,也是該事物的功能,需要明確出來,但是無法定義主體。通過抽象方法來表示。
2、抽象類比一般類多了個抽象函數。就是在類中可以定義抽象方法。
3、抽象類不可以實例化。
4、抽象類雖然不能創建對象,但是也有構造函數。供子類實例化調用。
注:1、被abstract修飾的函數不能同時被private、final、static修飾。
原因:
final:被final修飾的類不能有子類。而被abstract修飾的類一定是一個父類。
private:抽象類中的私有的抽象方法,不被子類所知,就無法被複寫。
而抽象方法出現的就是需要被複寫。
static:如果static可以修飾抽象方法,那麼連對象都省了,直接類名調用就可以了。
可是抽象方法運行沒意義。
2、抽象有一個特殊的地方:抽象類中可以不定義抽象方法。這樣做可以不讓本來實例化,也可以用於模塊設計。
如下面的小程序:
- /*
- 需求:獲取一段程序的運行時間
- 原理:將程序開始執行到執行結束的時間相減就是程序的運行時間了
- 思路:1、由於想要獲取的程序時未知的,可以將其抽象出去,通過子類繼承複寫的方式獲得程序
- 2、利用java中提供的當前時間功能記錄下程序開始執行和執行結束的時間,然後相減
- */
- abstract class GetTime
- {
- public final void getTime()//加final表示不能被複寫
- {
- long start=System.currentTimeMillis();//開始執行時間
- program();
- long end=System.currentTimeMillis();//執行結束時間
- System.out.println("毫秒"+(end-start));
- }
- abstract void program();//由於程序不確定,故抽象出去
- }
- //要獲取執行時間的程序
- class GetProgram extends GetTime
- {
- void program()
- {
- for(int x=0;x<1000;x++)
- System.out.print(x+" ");
- }
- }
- class TemplateDemo
- {
- public static void main(String[] args)
- {
- new GetProgram().getTime();
- // System.out.println("Hello World!");
- }
- }
第三講 接口
一、概述
接口,可以被認爲是一個特殊的抽象類。當抽象類中的方法都是抽象的,那麼該類可以通過接口的形式來表示。接口使用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修飾的權限。
接口實例小程序:
- //抽象學生類
- abstract class Student
- {
- //抽象的學習方法
- abstract void study();
- //共性內容非抽象的睡覺方法
- void sleep()
- {
- System.out.println("sleep");
- }
- }
- //接口,吸菸
- interface Smoking
- {
- void smoke();
- }
- //Zhangsan這個對象繼承學生類,實現吸菸接口
- class Zhangsan extends Student implements Smoking
- {
- //複寫學習方法
- void study()
- {
- System.out.println("Zhangsan_study");
- }
- //複寫吸菸方法
- public void smoke()
- {
- System.out.println("Zhangsan_smoking");
- }
- }
- //Lisi是好學生,不吸菸
- class Lisi extends Student
- {
- //複寫學習方法
- void study()
- {
- System.out.println("Lisi_study");
- }
- }
- class InterfaceDemo
- {
- public static void main(String[] args)
- {
- Zhangsan z = new Zhangsan();
- z.study();
- z.smoke();
- new Lisi().study();
- }