三、繼承
繼承:
繼承是類與類的一種關系,是一種“is a”的關系。比如說椭住,狗是一種動物(dog is an animal),汽車是一種交通工具(car is a vehicle)字逗,在這里動物和交通工具就稱為父類(基類)京郑,狗和汽車就稱為子類(派生類)。就像日常生活中我們所說的繼承一樣葫掉,兒子會繼承父親的一些相貌上或者性格上的特點些举,還會耳濡目染、有樣學樣地繼承父親的一些行為方式俭厚;而在Java中户魏,子類則會繼承父類所有的屬性和方法(當然private修飾的屬性和方法不可以繼承哦)。
繼承的關鍵字為extends
具體定義語法為:
[權(quán)限修飾符] class 類名 extends 父父類名{
//定義或修改屬性
//定義或重寫方法
}
注意:類是單繼承的挪挤,即每個類只能有一個父類叼丑。
方法的重寫與方法的重載:
上面說過子類可以繼承父類的方法,但如果父類中的方法不夠完善或者不能滿足子類的要求扛门,這時候子類就可以修改父類的方法鸠信,拓展功能或者重新定義,這就是方法的重寫论寨。
在同一個類中星立,我們可以定義一些名稱相同的方法爽茴,但這些方法的參數(shù)或者返回值類型卻不同。在調(diào)用方法時贞铣,雖然這些方法都是同名的闹啦,但Java會根據(jù)不同的參數(shù)列表來選擇正確的方法進行調(diào)用,這就是方法的重載辕坝。
方法的重寫和重載從字面上來看只有一字之差,但是本質(zhì)上卻有很大的區(qū)別荐健,以下是需要注意的幾點:
- 子類中重寫的方法與父類中的方法有完全相同的返回值類型酱畅、方法名、參數(shù)個數(shù)以及參數(shù)類型江场,只是方法體不同
- 重載的方法必須具有不同的參數(shù)列表纺酸,即不同的參數(shù)類型或者不同的參數(shù)個數(shù)或者不同的參數(shù)順序,因此方法體也就不同了址否。除此之外餐蔬,權(quán)限修飾符和返回值類型也可以不同,但方法名必須要相同
- 方法的重寫和重載都可以改變權(quán)限修飾符佑附,但都只能將范圍擴大(關于權(quán)限修飾符的作用范圍上文有介紹)
- 一般來說樊诺,重載方法時,方法之間需要存在一定的聯(lián)系音同,例如功能相似词爬,因為這樣才能使方法的重載有意義,并且提高程序的可讀性
super關鍵字:
如果子類已經(jīng)將父類中的方法重寫了权均,調(diào)用的時候肯定是調(diào)用被重寫過的方法顿膨,那如果現(xiàn)在一定要調(diào)用父類中的方法,此時就可以通過使用super關鍵字:super.方法名(參數(shù)列表)
來實現(xiàn)
下面以狗類(子類)和動物類(父類)為例具體演示一下上面介紹的幾個概念叽赊,先定義Dog類和Animal類:
package com.project;
public class Animal{//定義Animal類
int legs = 2;//定義legs屬性
public void eat(){//定義eat方法
System.out.println("動物具有吃東西的能力");
}
package com.project;
public class Dog extends Animal{//定義Dog類
}
修改項目測試類的代碼:
public class Test {
public static void main(String[] args) {
Dog obj = new Dog();//創(chuàng)建Dog類對象obj
System.out.println(obj.legs);//輸出obj的legs屬性值
obj.eat();//調(diào)用obj的eat()方法
}
}
控制臺界面會輸出以下信息:
說明子類可以繼承父類的屬性和方法恋沃。
修改Dog類的代碼:
public class Dog extends Animal{
int legs = 4;
public void eat(){//重寫eat()方法
super.eat();//用super關鍵字調(diào)用Animal類中的eat()方法
System.out.println("狗具有吃骨頭的能力");
}
}
其他代碼不作改動,控制臺界面會輸出以下信息:
說明子類可以修改父類的屬性和重寫父類的方法必指。
四囊咏、多態(tài)
多態(tài):
多態(tài),從字面上理解就是多種形態(tài)取劫,Java中指的是對象的多種形態(tài)匆笤。
多態(tài)分為兩種:
- 引用多態(tài):父類的引用既可以指向本類的對象,也可以引用子類的對象
- 方法多態(tài):當通過父類創(chuàng)建本類對象時谱邪,調(diào)用的方法為本類的方法炮捧;創(chuàng)建子類對象時,調(diào)用的方法為子類繼承的方法或重寫的方法(即不能調(diào)用子類獨有的方法)
還是以Dog類和Animal類為例惦银,修改Dog類和項目測試類主方法的代碼:
public class Dog extends Animal{
public void eat(){
System.out.println("狗具有吃骨頭的能力");
}
}
public class Test {
public static void main(String[] args) {
Animal obj1 = new Animal();//通過Animal類創(chuàng)建Animal類對象obj1
Animal obj2 = new Dog();//通過Animal類創(chuàng)建Dog類對象obj2(通過構(gòu)造方法可以區(qū)別創(chuàng)建的是哪類對象)
obj1.eat();//調(diào)用obj1的eat()方法
obj2.eat();//調(diào)用obj2重寫的eat()方法
}
}
控制臺界面會輸出以下信息:
再次修改Dog類和項目測試類主方法的代碼:
public class Dog extends Animal{
public void eat(){
System.out.println("狗具有吃骨頭的能力");
}
public void watchDoor(){//定義watchDoor方法
System.out.println("狗具有看門的能力");
}
}
public class Test {
public static void main(String[] args) {
Animal obj1 = new Animal();
Animal obj2 = new Dog()咆课;
obj1.eat();
obj2.eat();
obj2.watchDoor();//調(diào)用obj2的獨有的watchDoor方法
}
}
此時末誓,obj2.watchDoor();
這個地方程序會報錯:
因為父類中并沒有定義watchDoor()方法,通過父類創(chuàng)建子類對象并調(diào)用這個子類獨有的方法時就會報錯书蚪。
抽象類:
抽象類只是規(guī)定子類必須擁有的方法喇澡,但并不規(guī)定這些方法是如何實現(xiàn)的。因此殊校,可以從多個具有相同特征的類中抽象出一個抽象類晴玖,這個抽象類作為子類的模版,從而避免子類設計的隨意性为流。需要注意的是:
- 抽象類和抽象方法都是用
abstract
關鍵字來修飾 - 當
abstract
定義抽象方法時呕屎,只需要聲明即可,不需要定義具體實現(xiàn)(因為抽象類并不關注這些方法是如何實現(xiàn)的)敬察,即abstract 類名();//沒有方法體
- 抽象類中既可以有普通方法秀睛,也可以有抽象方法
- 包含抽象方法的類一定是抽象類
下面以狗類(子類)、貓類(子類)和動物類(父類莲祸,同時也是抽象類)為例具體演示一下上面介紹的幾個概念蹂安,先定義Dog類、Cat類和Animal類:
public abstract class Animal{//定義Animal抽象類
public abstract void eat();//定義eat抽象方法
public abstract void voice();//定義voice抽象方法
}
public class Dog extends Animal{
public void eat(){//定義eat()方法在Dog類中的具體實現(xiàn)
System.out.println("狗具有吃骨頭的能力");
}
public void voice(){//定義voice()方法在Dog類中的具體實現(xiàn)
System.out.println("狗“汪汪汪”地叫");
}
}
public class Cat extends Animal{
public void eat(){//定義eat()方法在Cat類中的具體實現(xiàn)
System.out.println("貓具有吃魚的能力");
}
public void voice(){//定義voice()方法在Cat類中的具體實現(xiàn)
System.out.println("貓“喵喵喵”地叫");
}
}
修改項目測試類的代碼:
public class Test {
public static void main(String[] args) {
Dog obj1 = new Dog();
Cat obj2 = new Cat();
obj1.eat();
obj1.voice();
obj2.eat();
obj2.voice();
}
}
控制臺界面會輸出以下信息:
接口:
接口定義的是某一批類所共同遵守的規(guī)范锐帜,既不關心這些類中的數(shù)據(jù)田盈,也不關心這些類中方法的具體實現(xiàn),只規(guī)定這些類中必須包含的方法(這一點與抽象類很相似)抹估。
定義接口的關鍵字為interface
缠黍。接口不同于類,它可以繼承多個父接口药蜻。具體的定義語法為:
[權(quán)限修飾符] [abstract] interface 接口名 [extends 父接口1, 父接口2, ...]{
//定義一個或多個常量
//定義一個或多個抽象方法
}
注意:
- 因為接口中包含的是常量和抽象方法瓷式,所以定義接口的時候系統(tǒng)會自動添加
abstract
關鍵字 - 接口中的屬性均為靜態(tài)常量,因此在定義屬性的時候系統(tǒng)會自動添加
public static final
修飾符 - 接口中的方法均為抽象方法语泽,因此在定義方法的時候系統(tǒng)會自動添加
public abstract
修飾符 - 接口是用來被繼承和被實現(xiàn)的贸典,因此不能使用
private
和protected
修飾(這樣會使得接口沒有意義),一般使用public
修飾
使用implements
關鍵字實現(xiàn)接口踱卵。而當類既繼承父類又實現(xiàn)接口時廊驼,定義語法為:
[權(quán)限修飾符] class 類名 extends 父類 implements 接口1, 接口2, ...{//一個類可以實現(xiàn)多個接口
//如果繼承了抽象類,要包含繼承的抽象方法惋砂;此外還要包含接口的抽象方法
}
注意:
- 在給接口命名的時候通常在名字前面加上一個“I”
- 繼承父類必須要在實現(xiàn)接口之前
還是以狗類妒挎、貓類為例,現(xiàn)在要他們都繼承哺乳動物類西饵。狗和貓都有吃東西和叫的能力酝掩,但狗能游泳而貓卻不能。在大自然中眷柔,鴨子也是會游泳的期虾,但很明顯原朝,鴨子并不屬于哺乳動物,即不能繼承哺乳動物類镶苞。因此要想描述狗和鴨子都具有游泳的能力喳坠,就要用到接口。
先定義ISwim接口:
package com.project;
public interface ISwim{
public void swim();
}
定義Mammal類(定義的代碼與Animal類一樣茂蚓,只是類名不同)壕鹉,修改Dog類和Cat類的代碼,:
public class Dog extends Mammal implements ISwim{//實現(xiàn)ISwim接口
public void eat(){
System.out.println("狗具有吃骨頭的能力");
}
public void voice(){
System.out.println("狗“汪汪汪”地叫");
}
public void swim(){//定義swim()方法在Dog類中的具體實現(xiàn)
System.out.println("狗具有游泳的能力");
}
}
public class Cat extends Mammal{
public void eat(){
System.out.println("貓具有吃魚的能力");
}
public void voice(){
System.out.println("貓“喵喵喵”地叫");
}
}
定義Duck類:
public class Duck implements ISwim{//實現(xiàn)ISwim接口
public void swim(){//定義swim()方法在Duck類中的具體實現(xiàn)
System.out.println("鴨子具有游泳的能力");
}
}
修改項目測試類主方法的代碼:
public class Test {
public static void main(String[] args) {
Dog obj1 = new Dog();
Cat obj2 = new Cat();
Duck obj3 = new Duck();
obj1.eat();
obj1.voice();
obj1.swim();
obj2.eat();
obj2.voice();
obj3.swim();
}
}
控制臺界面會輸出以下信息:
后記
以上的內(nèi)容是我通過看書和看視頻以及上網(wǎng)找資料歸納聋涨、總結(jié)出來的御板,目的在于為我今后復習Java基礎知識和編寫Java程序時提供可查閱的筆記,我也希望能夠給閱讀本文的Java初學者一些幫助牛郑。
參考資料
《Java——從入門到精通》
慕課網(wǎng)(IMOOC)