大家可以關(guān)注作者的賬號,關(guān)注從零開始學Java筆記文集。也可以根據(jù)目錄前往作者的博客園博客進行學習。本片文件將基于黑馬程序員就業(yè)班視頻進行學習以及資料的分享,并記錄筆記和自己的看法。歡迎大家一起學習和討論。
【從零開始學Java筆記】目錄
什么是繼承?
繼承就是子類繼承父類的特征和行為,使得子類對象(實例)具有父類的實例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。
簡單的說就是多個類有相同的成員變里和成員方法,為了避免代碼的重復(fù),可以先寫一個父類,包含共同的屬性,然后再由子類繼承。
關(guān)鍵字:extends
下面舉個例子:
- 不使用繼承
class GuanYu{
String name;
int age;
String address;
public void win() {
System.out.println("關(guān)羽贏了!");
}
public void lose() {
System.out.println("關(guān)羽輸了!");
}
}
class LvBu{
String name;
int age;
String address;
public void win() {
System.out.println("呂布贏了!");
}
public void lose() {
System.out.println("呂布輸了!");
}
}
可以看出無論是關(guān)羽還是呂布都擁有成員變量:姓名,年齡和地址和成員方法:贏和輸。如果想寫一百個武將,十分繁瑣。所以使用繼承,寫一個父類,先尋找他們的共性,那就是他們都是人,所以寫一個people類,包含他們共同的屬性和方法。如下:
class Person{
String name;
int age;
String address;
public void win() {
System.out.println("關(guān)羽贏了!");
}
public void lose() {
System.out.println("關(guān)羽輸了!");
}
}
class GuanYu extends Person{
}
class LvBu extends Person{
}
Java中維承的特點
- Java語言只支持單一繼承,只能繼承一個父類(一個兒子只能有一個親爹)
Java語言支持多層繼承(一個兒子可以有一個親爹, 還可以有一個親爺爺)
繼承中成員變量的特點
- 子類只能獲取父類非私有成員
子父類中成員變量的名字不一樣 直接獲取父類的成員變里
子父類中成員變量名字是一樣的獲取的是子類的成員變量
class GuanYu{
private String wifeName = "null";
String name = "GuanYu";
}
class GuanXing extends GuanYu{
String name = "GuanXing";//如果沒有這句,show()輸出GuanYu
public void show() {
// System.out.println(wifename); 子類無法繼承父類的私有變量,報錯
System.out.println(name);//輸出GuanXing
}
給大家出一道題,大家思考一下三個輸出語句的結(jié)果,如果能理解基本上就沒什么問題了
這里為大家補充一個就近原則:誰離我近我就用誰
如果有局部變量就使用局部變量
如果沒有局部變量,有子類的成員變量就使用子類的成員變量
如果沒有局部變量和子類的成員變量,有父類的成員變量就使用父類的成員變量
啥都沒有,出錯了! ! !|
class GuanYu{
String name = "關(guān)羽";
}
class GuanXing extends GuanYu{
String name = "關(guān)興";
public void show() {
String name = "關(guān)平";
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
super :可以獲取父類的成員變量和成員方法
this:可以獲取當前類的成員變量和成員方法
輸出結(jié)果
關(guān)平
關(guān)興
關(guān)羽
繼承中成員方法的特點
和成員變量相似
- 子類中沒有這個方法,調(diào)用父類的
子類中重寫了這個方法,調(diào)用子類的
重寫和重載的區(qū)別
方法的重寫:在子父類當中,子類的方法和父類的完全一樣,子類重寫了父類的方法(覆蓋),當子類重寫了父類的方法之后,使用子類對象調(diào)用的就是子類的方法
方法的重載:在一個類中,有多個重名的方法,但是其參數(shù)不一樣(參數(shù)的個數(shù),參數(shù)的類型,參數(shù)的順序),和返回值無關(guān)
方法重寫的應(yīng)用場景
- 當父類的方法不能完全滿足子類使用,這個時候子類重寫父類的方法
并可以在方法中使用關(guān)鍵字super調(diào)用父類的方法,這樣做即可以保有父類的功能,也可以擁有子類持有的功能
這里給大家舉個例子
class GuanYu{
public void attack() {
System.out.println("拖刀");
}
}
class GuanXing extends GuanYu{
public void attack() {
super.attack();
System.out.println("斬");
}
其實很簡單,關(guān)興繼承了父親的攻擊方式,但是在拖刀的前提下加入了斬,使威力更強。這里為什么使用super.attack()為什么不直接復(fù)制過來,這里可以想象拖刀是一個很復(fù)雜的過程,但是我們這里簡寫,如果關(guān)羽攻擊的函數(shù)有1000行代碼,調(diào)用比復(fù)制更方便,也更好看。
方法重寫的注意事項
不能重寫父類私有的方法
權(quán)限必須大于等于父類方法的權(quán)限(了解即可)
注解: @ 一般寫在方法、變量、類前面,用來描述方法、變量、類,目的是提高代碼規(guī)范
還用剛才那個例子
class GuanYu{
public void attack() {
System.out.println("拖刀");
}
}
class GuanXing extends GuanYu{
// public void attck() {
// super.attack();
// System.out.println("斬");
// }
public void attack(String a) {
super.attack();
System.out.println("斬");
}
如果我們給子類的方法加一個形參 string a ,或者錯寫成attck()并不會報錯,但是這個已經(jīng)不算是方法的重寫了
這時候我們在重寫的代碼前加上@Override,就會報錯。
繼承中構(gòu)造方法的執(zhí)行順序
public class ExtendsDemo2 {
public static void main(String[] args) {
GuanYu gy = new GuanYu();
System.out.println("****************");
GuanXing gx = new GuanXing();
}
}
class GuanYu{
public GuanYu() {
System.out.println("這是關(guān)羽的無參構(gòu)造");
}
public GuanYu(int a) {
System.out.println("這是關(guān)羽的有參構(gòu)造");
}
}
class GuanXing extends GuanYu{
public GuanXing() {
System.out.println("這是關(guān)興的無參構(gòu)造");
}
public GuanXing(int a) {
System.out.println("這是關(guān)興的有參構(gòu)造");
}
}
輸出結(jié)果
這是關(guān)羽的無參構(gòu)造
****************
這是關(guān)羽的無參構(gòu)造
這是關(guān)興的無參構(gòu)造
為什么調(diào)用子類的無參構(gòu)造的時候,也會調(diào)用父類的無參構(gòu)造?
在有子父類繼承關(guān)系的類中,創(chuàng)建子類的對象,調(diào)用子類的構(gòu)造方法,如果子類構(gòu)造方法的第一行代碼沒有調(diào)用父類的構(gòu)造方法,則會默認的調(diào)用父類的無參構(gòu)造
我們可以使用super( )在子類構(gòu)造方法的第一行中調(diào)用父類的構(gòu)造方法
class GuanXing extends GuanYu{
public GuanXing() {
//super(1); //測試1
//this(2); //測試2
System.out.println("這是關(guān)興的無參構(gòu)造");
}
public GuanXing(int a) {
System.out.println("這是關(guān)興的有參構(gòu)造");
}
可以分別取消測試1和測試2的注釋,再運行,看看結(jié)果。
為什么會有這個設(shè)定呢?因為必須先執(zhí)行父類的構(gòu)造,要先給父類的成員變里進行初始化,子類可能會使用到。
this和super的區(qū)別
this:當前對象的引用
調(diào)用子類的成員變量
調(diào)用子類的成員方法
在子類的構(gòu)造方法第一行調(diào)用子類其他構(gòu)造方法
super:子類對象的父類引用
調(diào)用父類的成員變量
調(diào)用父類的成員方法
在子類的構(gòu)造方法第一行調(diào)用父類的構(gòu)造方法
繼承的優(yōu)缺點
優(yōu)點
- 提高了代碼的復(fù)用性
- 提高了代碼的可維護性
缺點
- 類的耦合性增強了
- 開發(fā)的原則:高內(nèi)聚低耦合
- 內(nèi)聚:就是自己完成某件事情的能力
- 耦合:類與類的關(guān)系
通俗易懂的來說就是繼承可以只通過修改父類的屬性來實現(xiàn)子類屬性的同步修改,這樣會很方便。例如,奧迪,寶馬都是汽車的子類,如果想讓所有品牌汽車的價格增加15%,只需要再父類里面進行操作即可。但是同時也會出現(xiàn)問題,父類的屬性進行修改,子類的屬性必定進行修改,但有時或出現(xiàn)錯誤。例如刪掉增加15%的價格,所有的品牌都會自動刪除,如果有一些其他和價格有關(guān)的方法就會出現(xiàn)錯誤。其實這樣就是高耦合的表現(xiàn),類與類之間關(guān)系十分緊密,牽一發(fā)而動全身。