繼承
Java物件導向的第二個特性:繼承,繼承是指新的類可以獲得已有類(稱為父類或基類)的屬性和行為,稱新類為已有類的派生類或子類,繼承是一種聯結類的層次模型,為類的重用提供方便,也可以說複用程式碼,例如有如下兩個類Man類和Woman類:
以上兩個類中,我們可以看出,男人和女人的屬性有很多相同的地方,男人和女人都是人,他們都具備人所具備的屬性和行為,例如,姓名。年齡,性別,吃飯,睡覺等等,如果我們可以最大限度的複用程式碼,提取出兩個類所共有的屬性和行為,那麼如何來實現程式碼的複用,這就要Java物件導向的特性二,繼承性,繼承就是使用已經存在類來定義新的類,新類可以增加新的屬性和行為,也可以使用父類的屬性和行為,但是不能選擇性的繼承父類,使用繼承可以方便的複用程式碼,提高開發效率,使用繼承可以使程式結構清晰,但是會增加程式碼耦合度。 使用繼承後的類設計如下: 使用繼承需要明確的是: 1.Java繼承使用extends關鍵字實現 2.Java是支援單繼承。 3.子類擁有父類非private的屬性和方法 4.子類可以擁有自己的屬性和方法,也就是說子類可以對父類進行擴充套件 5.子類可以重寫父類的方法,涉及到方法的重寫,將會在後面學習 講到繼承,就會說到構造器,protected關鍵字,向上轉型。構造器
子類可以繼承父類非private的屬性和方法,還存在一種是子類不能繼承的,那就是構造器,對於構造器來說,他允許被子類呼叫,不允許被子類繼承,呼叫父類的構造方法使用super()即可。 這裡就涉及到構造器初始化順序的事,父類構造器如下:
public Person() {
System.out.println("我是父類構造器");
}
public Person(String name, String sex, int age) {
System.out.println("我是父類含參構造器");
this.name = name;
this.sex = sex;
this.age = age;
}
複製程式碼
子類構造器如下:
public Man() {
System.out.println("我是子類構造器");
}
public Man(boolean smook) {
System.out.println("我是子類含參構造器");
}
複製程式碼
初始化物件:
Man man = new Man();
複製程式碼
輸出結果如下:
我是父類構造器
我是子類構造器
複製程式碼
初始化子類物件時會預設呼叫父類預設構造器,前提是父類要有預設的無參構造器,如果父類沒有預設的無參構造器,我們就必須通過super()來呼叫父類構造器。例如: 父類有構造器:
public Person(String name) {
System.out.println("我是父類含參構造器====="+name);
}
複製程式碼
子類預設構造器如下:
public Man() {
super("張三");
System.out.println("我是子類構造器");
}
複製程式碼
初始化子類物件:
Man man = new Man();
複製程式碼
輸出結果:
我是父類含參構造器=====張三
我是子類構造器
複製程式碼
綜上所述:對於繼承來講,子類會預設呼叫父類的預設無參構造器(前提是父類存在預設無參構造器),如果父類沒有預設的構造器,子類就必須明確的指定自己要呼叫的是父類哪一個構造器,而且必須是在子類構造器中最前面做的事,就是程式碼寫在最前面。
protected關鍵字
首先protected是一個許可權修飾符,所以我們先看看許可權修飾符的相關知識:
四種不同修飾符的許可權如下所示:
1.public:當前類,同包,子類,其他包 2.protected:當前類,同包,子類 3.default:當前類,同包 4.private:當前類 類的成員不寫訪問修飾符就相當於default,default對於同一個包中的其他類相當於公開,對於不是同一個包的其他類相當於私有。protected對於子類相當於公開,對於不是同包也沒有子類關係的類相關於私有。 對於Java物件導向的封裝性來講,private是最好的選擇,但是有時候我需要將一些屬性儘可能的向外界隱藏,但是允許子類可以訪問,天下父母都一樣,儘可能的向多給子類一些,但是又不想給全世界,畢竟沒有那麼偉大,所以就使用到了protercted關鍵字。例如: 父類protected 方法:
protected void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "父類toString方法=="+name;
}
複製程式碼
子類toString方法:
@Override
public String toString() {
setName("我是張三");//呼叫父類protected方法
return super.toString();//呼叫父類toString方法
}
複製程式碼
例項化子類物件:
Man man = new Man();
System.out.println(man.toString());
複製程式碼
輸出結果為:
父類toString方法==我是張三
複製程式碼
綜上所述:我們可以看出子類Man類可以呼叫父類Person的setName(),因為改方法使用protected許可權修飾符,儘管可以如此,但是最好將屬性的許可權保持為private,更好的體現Java物件導向的封裝性,通過protected方法來控制繼承者的訪問許可權。
向上轉型
這個其實也叫子類物件的多型性,Java物件導向的特性之多型性將在後續的學習中,向上轉型就是父類的應用指向子類物件,例如:
Person person = new Man();
複製程式碼
具體例項如下所示,例如在父類Person中有如下方法:
public void show(){
System.out.println("我是父類show方法");
}
static void show(Person person){
person.show();
}
複製程式碼
Man類繼承Person類,在外部直接呼叫Man類的父類的靜態方法如下:
Man.show(person);
複製程式碼
按理說我們應該在show方法中傳入Person物件,但是我們可以參這樣做:
Person man = new Man();
Man.show(man);
複製程式碼
另外:在這裡可以通過man呼叫父類的方法,如果子類重寫了父類的方法,那麼呼叫就會執行子類的方法,這個也叫虛擬方法呼叫,也就是說man不能呼叫子類所特有的方法。 當然,如果你想呼叫子類所特有的方法,那麼可以使用強轉,
Man m = (Man)man;
複製程式碼
使用m來呼叫子類所特有的方法。
注意
雖然說繼承可以帶來很多好處,可以實現程式碼複用,但是使用繼承要慎重,為什麼這麼講呢?原因是: 1.增強了程式碼之間的耦合度。父類變,子類也就必須跟著變,有點像家族企業的興衰一樣 2.繼承破壞了封裝,對於父類而言,實現細節對子類是很清晰的 繼承有優點也有缺點,不知道應不應該使用繼承,主要看自己的程式碼需不需要繼承帶來的好處,例如需要向上轉型不,如果需要,那肯定需要繼承。