知識(shí)點(diǎn)
什么是繼承
繼承是Java面向?qū)ο笕筇匦裕ǚ庋b、繼承洽瞬、多態(tài))之一,用extends關(guān)鍵字表示繼承儡首,比如有A類片任、B類偏友,B類繼承A類蔬胯,如下寫法:
public class B extends A{ }
通常我們管A類叫父類,管B類叫子類位他。
如果一個(gè)類沒(méi)有寫extends關(guān)鍵字氛濒,那這個(gè)類默認(rèn)繼承java.lang.Object類,Object類是所有類的祖先類鹅髓。何時(shí)用繼承
繼承通常是為了消除代碼的重復(fù)舞竿、冗余,使代碼更易維護(hù)窿冯。說(shuō)白了就是將一些公共的屬性骗奖、方法提取出來(lái),放到一個(gè)通用的類中醒串,然后有需要的類再繼承這個(gè)通用的類执桌。
比如普通員工和經(jīng)理,他們都享有公司五險(xiǎn)一金的基本福利芜赌,普通員工每年有一次國(guó)內(nèi)游的福利仰挣,經(jīng)理每年有一次帶家人國(guó)內(nèi)游以及一次國(guó)外旅游的福利。這里很明顯可以把五險(xiǎn)一金福利放到父類中缠沈,因?yàn)橹灰枪締T工就有膘壶,這是公共的福利错蝴。詳見(jiàn)下文實(shí)例分析。繼承的限制
final類是不允許被繼承的颓芭,final方法是不允許被子類重寫的顷锰。通過(guò)關(guān)鍵字就很好理解,final是最終的意思畜伐,既然是最終了馍惹,那也就不會(huì)有下一層級(jí)的子類了。
不允許多繼承(接口可以彌補(bǔ)這個(gè)缺陷玛界,在接口中詳解)万矾。比如有A類、B類慎框、C類三個(gè)類良狈,C類不能同時(shí)繼承A類、B類:public class C extends A,B { }
以上寫法是錯(cuò)誤的笨枯。繼承中子類擁有的權(quán)限
子類擁有父類所有非private的屬性和方法薪丁;
子類可以擁有自己的屬性和方法;
子類可以重寫父類非final馅精、static聲明的方法严嗜;super與this關(guān)鍵字
通過(guò)super關(guān)鍵字可以訪問(wèn)父類非private的屬性、方法洲敢、構(gòu)造器漫玄,比如要在子類中訪問(wèn)父類的test()方法,可以用super.test()压彭,要訪問(wèn)父類的構(gòu)造器則是通過(guò)super()可以訪問(wèn)到父類的無(wú)參構(gòu)造器睦优,如果要訪問(wèn)有參構(gòu)造器則在括號(hào)中帶上參數(shù)即可;
通過(guò)this關(guān)鍵字壮不,可以訪問(wèn)子類所有的屬性汗盘、方法、構(gòu)造器询一,說(shuō)白了就是指當(dāng)前類的引用了隐孽。
注意:很多人認(rèn)為super與this引用是一樣的概念,實(shí)際不是的健蕊。this是當(dāng)前對(duì)象的引用菱阵,可以直接賦值給另一個(gè)對(duì)象變量,即可以使用Object obj = this;
绊诲;而super其實(shí)是Java一個(gè)特殊關(guān)鍵字送粱,可以調(diào)用父類的非private的屬性、方法掂之、構(gòu)造器抗俄,但不能賦值給另一個(gè)對(duì)象變量脆丁,也就是不能使用Object obj = super;
繼承中的構(gòu)造器
詳細(xì)可以查看我的這篇文章java 構(gòu)造器(構(gòu)造方法)使用詳細(xì)說(shuō)明
實(shí)例
需求:公司有普通員工和經(jīng)理,他們都享有公司五險(xiǎn)一金的基礎(chǔ)福利动雹,普通員工每年有一次國(guó)內(nèi)游的福利槽卫,經(jīng)理每年有一次帶家人國(guó)內(nèi)游以及一次國(guó)外旅游的福利。分別打印出普通員工的福利和經(jīng)理的福利胰蝠。
1.按沒(méi)有繼承的做法
定義普通員工類:
/**
* 員工類
*/
public class Employee {
/**
* 基本福利
*/
private String basicWelfare;
/**
* 國(guó)內(nèi)旅游福利
*/
private String internalTour;
/**
* 構(gòu)造函數(shù)歼培,初始化福利
*/
public Employee(){
this.basicWelfare = "五險(xiǎn)一金";
this.internalTour = "一年一次國(guó)內(nèi)游";
}
/**
* 打印員工福利
*/
public void printWelfare(){
System.out.println(this.basicWelfare);
System.out.println(this.internalTour);
}
}
定義經(jīng)理類
/**
* 經(jīng)理
*/
public class Manager{
/**
* 基本福利
*/
private String basicWelfare;
/**
* 國(guó)內(nèi)旅游福利
*/
private String internalTour;
/**
* 國(guó)外旅游福利
*/
private String externalTour;
/**
* 構(gòu)造函數(shù),初始化福利
*/
public Manager(){
this.basicWelfare = "五險(xiǎn)一金";
this.internalTour = "一年一次帶家人國(guó)內(nèi)游";
this.externalTour = "一年一次國(guó)外旅游";
}
/**
* 打印員工福利
*/
public void printWelfare(){
System.out.println(this.basicWelfare);
System.out.println(this.internalTour);
System.out.println(this.externalTour);
}
}
以上兩個(gè)類茸塞,可以看到basicWelfare躲庄、internalTour兩個(gè)屬性以及printWelfare()方法是重復(fù)的。重復(fù)必然導(dǎo)致難維護(hù)钾虐!如果需求改為基本福利是六險(xiǎn)一金以及1000塊春節(jié)過(guò)節(jié)費(fèi)噪窘,那這兩個(gè)類都要改過(guò)去,不方便維護(hù)效扫,特別是類越多倔监,維護(hù)難度越大。此時(shí)繼承就能盡顯其優(yōu)勢(shì)菌仁!看以下例子浩习。
2. 按繼承的做法
分析需求,可以看到經(jīng)理的福利基本上是包含了普通員工的福利济丘,所以將員工類作為父類谱秽,并稍加改造,增加可以修改國(guó)內(nèi)旅游屬性的方法setInternalTour(String internalTour)闪盔,主要是因?yàn)閕nternalTour屬性是private的弯院,不能在子類訪問(wèn)到辱士,所以開(kāi)放了一個(gè)方法供子類調(diào)用泪掀。這個(gè)改造主要是因?yàn)榻?jīng)理的國(guó)內(nèi)游還可以帶上家人。
定義員工類(父類)
/**
* 員工類
*/
public class Employee {
/**
* 基本福利
*/
private String basicWelfare;
/**
* 國(guó)內(nèi)旅游福利
*/
private String internalTour;
/**
* 初始化員工福利
*/
public Employee(){
this.basicWelfare = "五險(xiǎn)一金";
this.internalTour = "一年一次國(guó)內(nèi)游";
}
/**
* 可以設(shè)置國(guó)內(nèi)游的方法
* @param internalTour
*/
public void setInternalTour(String internalTour){
this.internalTour = internalTour;
}
/**
* 打印員工福利
*/
public void printWelfare(){
System.out.println(this.basicWelfare);
System.out.println(this.internalTour);
}
}
定義經(jīng)理類(子類)颂碘,繼承員工類
/**
* 經(jīng)理類
*/
public class Manager extends Employee{
/**
* 國(guó)外旅游福利
*/
private String externalTour;
/**
* 初始化經(jīng)理福利
*/
public Manager(){
//由于經(jīng)理國(guó)內(nèi)游還可以帶家人异赫,所以這里通過(guò)super.setInternalTour方法重新設(shè)置
super.setInternalTour("一年一次帶家人國(guó)內(nèi)游");
this.externalTour = "一年一次國(guó)外旅游";
}
/**
* 重寫父類的printWelfare()方法
* 由于父類已經(jīng)有printWelfare()方法并且可以打印基本福利和國(guó)內(nèi)游福利,
* 所以直接通過(guò)super調(diào)用父類的printWelfare()方法打印基本福利和國(guó)內(nèi)游福利
*/
@Override
public void printWelfare(){
//調(diào)用父類打印基本福利和國(guó)內(nèi)游福利头岔,
//這里必須帶上super塔拳,否則就是調(diào)用子類的printWelfare(),那就是死循環(huán)了
super.printWelfare();
//打印國(guó)外游福利
System.out.println(this.externalTour);
}
}
測(cè)試類
public class ExtendsDemo {
public static void main(String[] args){
//打印員工福利
Employee employee = new Employee();
System.out.println("員工福利:");
employee.printWelfare();
//打印經(jīng)理福利
Manager manager = new Manager();
System.out.println("員工福利:");
manager.printWelfare();
}
}
執(zhí)行以上測(cè)試類峡竣,輸出:
員工福利:
五險(xiǎn)一金
一年一次國(guó)內(nèi)游
員工福利:
五險(xiǎn)一金
一年一次帶家人國(guó)內(nèi)游
一年一次國(guó)外旅游
通過(guò)該繼承的實(shí)例改造靠抑,就能很方便完成以上提出的需求改造,如果基本福利改為六險(xiǎn)一金适掰,那只要將Employee類中的五險(xiǎn)一金改為六險(xiǎn)一金即可颂碧;如果要增加一項(xiàng)基本福利荠列,那也直接在Employee類改造即可。
源碼獲取
以上示例都可以通過(guò)我的GitHub獲取完整的代碼载城,點(diǎn)擊獲取