一、介紹
繼承是面向?qū)ο笞铒@著的一個(gè)特性。繼承是從已有的類(lèi)中派生出新的類(lèi),新的類(lèi)能吸收已有類(lèi)的數(shù)據(jù)屬性和行為,并能擴(kuò)展新的能力。Java繼承是使用已存在的類(lèi)的定義作為基礎(chǔ)建立新類(lèi)的技術(shù),新類(lèi)的定義可以增加新的數(shù)據(jù)或新的功能,也可以用父類(lèi)的功能,但不能選擇性地繼承父類(lèi)。這種技術(shù)使得復(fù)用以前的代碼非常容易,能夠大大縮短開(kāi)發(fā)周期,降低開(kāi)發(fā)費(fèi)用。
在面向?qū)ο蟪绦蛟O(shè)計(jì)中運(yùn)用繼承原則,就是在每個(gè)由一般類(lèi)和特殊類(lèi)形成的一般——特殊結(jié)構(gòu)中,把一般類(lèi)的對(duì)象實(shí)例和所有特殊類(lèi)的對(duì)象實(shí)例都共同具有的屬性和操作一次性地在一般類(lèi)中進(jìn)行顯式的定義,在特殊類(lèi)中不再重復(fù)地定義一般類(lèi)中已經(jīng)定義的東西,但是在語(yǔ)義上,特殊類(lèi)卻自動(dòng)地、隱含地?fù)碛兴囊话泐?lèi)(以及所有更上層的一般類(lèi))中定義的屬性和操作。特殊類(lèi)的對(duì)象擁有其一般類(lèi)的全部或部分屬性與方法,稱(chēng)作特殊類(lèi)對(duì)一般類(lèi)的繼承。
比如可以先定義一個(gè)類(lèi)叫車(chē),車(chē)有以下屬性:車(chē)體大小,顏色,方向盤(pán),輪胎,而又由車(chē)這個(gè)類(lèi)派生出轎車(chē)和卡車(chē)兩個(gè)類(lèi),為轎車(chē)添加一個(gè)小后備箱,而為卡車(chē)添加一個(gè)大貨箱。
二、知識(shí)點(diǎn)介紹
1、繼承概念
2、繼承的定義及使用格式
3、繼承注意事項(xiàng)
4、方法重寫(xiě)
三、上課對(duì)應(yīng)視頻的說(shuō)明文檔
1、繼承概念
1.1、繼承概述
繼承是面向?qū)ο蟮暮诵奶匦裕敲嫦驅(qū)ο蟮膶W(xué)習(xí)重點(diǎn)。同時(shí)繼承是代碼復(fù)用的重要方式,可以表示類(lèi)與類(lèi)之間的關(guān)系,是所有面向?qū)ο笳Z(yǔ)言不可缺少的組成部分。
1.2、繼承概念
當(dāng)一個(gè)類(lèi)的屬性與行為均與現(xiàn)有類(lèi)相似,屬于現(xiàn)有類(lèi)的一種時(shí),這一個(gè)類(lèi)可以定義為現(xiàn)有類(lèi)的子類(lèi)。
或者換成相反的角度來(lái)看,如果多個(gè)類(lèi)具有相同的屬性和行為,我們可以抽取出共性的內(nèi)容定義父類(lèi),這時(shí)再創(chuàng)建相似的類(lèi)時(shí)只要繼承父類(lèi)即可。
子類(lèi)擁有父類(lèi)的所有屬性與方法,無(wú)需重新定義。并且可以直接使用非私有的父類(lèi)成員。
從類(lèi)與類(lèi)之間的設(shè)計(jì)關(guān)系來(lái)看,子類(lèi)必須屬于父類(lèi)的一種時(shí),才會(huì)繼承。
我們?cè)谕瓿梢粋€(gè)龐大項(xiàng)目體系的時(shí)候,都是將共性的內(nèi)容抽取出,后續(xù)構(gòu)建過(guò)程是從各種父類(lèi)“向外”擴(kuò)散的。
下例展示了一個(gè)繼承關(guān)系
圖1-1 動(dòng)物繼承關(guān)系圖
動(dòng)物類(lèi)可以有姓名、年齡的成員變量,可以有吃飯、睡覺(jué)的方法。
所有貓科與犬科均有動(dòng)物的成員變量與成員方法,且貓科與犬科均屬于動(dòng)物,所以貓科與全科均可以繼承動(dòng)物類(lèi)。
貓科可以在動(dòng)物的基礎(chǔ)上再添加抓老鼠的方法
犬科可以在動(dòng)物的基礎(chǔ)上再添加看門(mén)的方法
犬科與貓科仍可以繼續(xù)出現(xiàn)子類(lèi),如波斯貓、巴厘貓、沙皮狗、斑點(diǎn)狗等,而其子類(lèi)仍可以再出現(xiàn)該品種的特性。
2、繼承定義及使用格式
2.1、繼承定義
class 子類(lèi) extends 父類(lèi){
//父類(lèi)的非私有方法與屬性均繼承過(guò)來(lái)
}
如:
父類(lèi)的定義:
class Person{
private String name;
public void eat(){
System.out.println(“吃飯”);
}
get/set方法
}
子類(lèi)繼承父類(lèi)的定義:
class Chinese extends Person{}
2.2、繼承使用
繼承關(guān)系的產(chǎn)生通常是為了定義出功能更為具體、更為強(qiáng)大的子類(lèi)。所以,定義子類(lèi)后,一般創(chuàng)建子類(lèi)對(duì)象使用。子類(lèi)可以直接使用父類(lèi)非私有的成員變量與成員方法
(注:如果成員變量沒(méi)有使用private修飾,則子類(lèi)也可直接訪問(wèn)。)
子類(lèi)的使用:
class Test{
public static void main(String[] args) {
Chinese? c = new Chinese();
c.setName(“張大力”);
String name = c.getName();
System.out.println(name);//打印結(jié)果為張大力
c.eat();? //打印結(jié)果吃飯
}
3、繼承注意事項(xiàng)
Java只支持單繼承,不支持多繼承。即只能有一個(gè)父類(lèi)。
父類(lèi)可以繼續(xù)有父類(lèi)。
所有類(lèi)均有父類(lèi),只有Object類(lèi)沒(méi)有父類(lèi)。
在所有使用父類(lèi)類(lèi)型的地方均可以傳入其子類(lèi)對(duì)象。
/*
* Animal的類(lèi)
* 屬性
*? ? ? ? name
*? ? ? ? age
* 行為
*? ? ? ? 吃
*? ? ? ? 睡
*/
public class Animal {
//成員變量
private String name;
private int age;
// //吃
// public abstract void eat(){
//? ? System.out.println(“吃”);
//? ? }
//睡
public void sleep(){
System.out.println("睡");
}
//-----------get/set-------------------
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
/*
*定義一個(gè)貓類(lèi)
* 屬性
*? name?
*? age
*? kind
* 行為
*? 吃
*? 睡
*? 抓老鼠
*/
public class Cat extends Animal{
private String kind;
// @Override
// public void eat(){
//? System.out.println("貓吃魚(yú)");
// }
//貓?zhí)赜械墓δ? 抓老鼠
public void catchMouse(){
System.out.println("抓耗子");
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
}
/*
*定義一個(gè)狗類(lèi)
* 屬性
*? name?
*? age
*? kind
* 行為
*? 吃
*? 睡
*? 看門(mén)
*/
public class Dog extends Animal{
private String kind;
// @Override
// public void eat(){
//? System.out.println("狗吃肉");
// }
//狗特有功能? 看門(mén)
public void lookDoor(){
System.out.println("看門(mén)");
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
}
/*
* 自定義類(lèi)型 家
*
*? 地址
*
* 行為
*? 在家吃飯
*/
public class Home {
private String address;
//動(dòng)物在家吃飯
//在所有使用父類(lèi)類(lèi)型的地方均可以傳入其子類(lèi)對(duì)象。
public void eatAtHome(Animal a){
//調(diào)用Animal的eat方法
//a.eat();?
}
//狗在在家吃飯
// public void eatAtHome(Dog dog){
//? System.out.println("狗在家吃了");
//? //調(diào)用狗的eat方法
//? dog.eat();
// }
//貓?jiān)诩页燥?/p>
// public void eatAtHome(Cat cat){
//? System.out.println("貓?jiān)诩俪粤?);
//? //調(diào)用貓的eat方法
//? cat.eat();
// }
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
/**
* 測(cè)試家類(lèi)
*/
public class Test {
public static void main(String[] args) {
//? 創(chuàng)建Home對(duì)象
Home home = new? Home();
//? Animal a = new Animal();?
//? home.eatAtHome(a);?
//在所有使用父類(lèi)類(lèi)型的地方均可以傳入其子類(lèi)對(duì)象。
Dog d = new Dog();
home.eatAtHome(d);
Cat c = new Cat();
home.eatAtHome(c);?
}
}
4、方法重寫(xiě)
4.1、方法重寫(xiě)概念
當(dāng)子類(lèi)繼承父類(lèi)后,擁有了父類(lèi)的成員并可以直接調(diào)用父類(lèi)非私有方法。如果子類(lèi)認(rèn)為父類(lèi)提供的方法不夠強(qiáng)大,子類(lèi)可以按照子類(lèi)自身的邏輯重新定義繼承過(guò)來(lái)的父類(lèi)方法,這個(gè)重新定義一個(gè)方法的過(guò)程叫做方法重寫(xiě)。
(注:在學(xué)習(xí)完多態(tài)和抽象類(lèi)后我們會(huì)對(duì)方法重寫(xiě)有更深的理解)
4.2、方法重寫(xiě)格式
子類(lèi)中定義與父類(lèi)一樣的方法便將父類(lèi)的方法重寫(xiě)了。此時(shí),當(dāng)創(chuàng)建子類(lèi)對(duì)象,調(diào)用方法時(shí),會(huì)調(diào)用子類(lèi)重寫(xiě)后的方法。如:
子類(lèi)中定義與父類(lèi)一樣的方法聲明即是方法重寫(xiě)。
如:
父類(lèi)定義:
public class Person{
private String name;
public void eat(){
System.out.println(“吃飯”);
}
get/set
}
子類(lèi)定義:
public class Chinese extends Person{
@override //@override是用于強(qiáng)制規(guī)定當(dāng)前定義的方法一定為重寫(xiě)的方法
public void eat() {
System.out.println(“按照中國(guó)的習(xí)慣,使用筷子吃”);
}
}
子類(lèi)的使用:
public class Test{
public static void main(String[] args) {
Chinese? c = new Chinese();
c.setName(“張大力”);? //父類(lèi)繼承方法直接調(diào)用
String name = c.getName(); //父類(lèi)繼承方法直接調(diào)用
System.out.println(name); //打印結(jié)果為張大力
c.eat();? //方法重寫(xiě)后調(diào)用的為重寫(xiě)后的方法
//打印結(jié)果:按照中國(guó)的習(xí)慣,使用筷子吃
}
}
/**
* 自定義類(lèi)型? 人類(lèi)
*
*? ? 姓名? 年齡
*/
public class Person {
String address;
private String name;
private int age;
public void eat(){
System.out.println("吃");? ?
}
public void sleep(){
System.out.println("睡");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
/*
* 定義類(lèi)型? 學(xué)生類(lèi)
*
* 姓名? 年齡
*
* 繼承
*? 概念1? 當(dāng)定義一個(gè)類(lèi)時(shí),發(fā)現(xiàn)現(xiàn)有類(lèi)與要定義的類(lèi)類(lèi)似,并且要定義的類(lèi)屬于現(xiàn)有類(lèi)的一種時(shí),
*? 就可以將這個(gè)類(lèi)定義為現(xiàn)有類(lèi)的子類(lèi)
*?
*? 子類(lèi)擁有父類(lèi)的所有屬性與方法,無(wú)需重新定義。并且可以直接使用非私有的父類(lèi)成員。
*?
*? 父類(lèi)私用的成員變量? 可以使用get/set方法 訪問(wèn)
*? 父類(lèi)私有的方法? 沒(méi)有辦法直接方法? 雖然繼承了 但是相當(dāng)于沒(méi)有
*? ?
*? 子類(lèi)可以有自己特有的屬性和方法
*?
*? 方法重寫(xiě)
*? ? 子類(lèi)繼承父類(lèi)后,可以直接使用父類(lèi)的非私有成員,但是如果覺(jué)得父類(lèi)的成員方法不夠強(qiáng)大,子類(lèi)可以按照自身的邏輯
*? ? 將繼承過(guò)來(lái)的父類(lèi)方法,進(jìn)行重寫(xiě)(方法重寫(xiě),方法復(fù)寫(xiě),方法覆蓋)
*?
*? 可以使用@Override來(lái)驗(yàn)證你的方法是不是重寫(xiě)方法。
*/
public class Student extends Person{
private String number;
public void method(){
System.out.println(address);
System.out.println(getName());
}
//重寫(xiě)父類(lèi)eat方法
@Override
public void eat(){
System.out.println("學(xué)生吃學(xué)生套餐");
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
/*
* 測(cè)試?yán)^承后的Studnet
*/
public class Test {
public static void main(String[] args) {
//創(chuàng)建Studnet對(duì)象
Student s = new Student();
s.setName("柳柳");
s.setNumber("0900112");
s.eat();
//? s.sleep();
String name = s.getName();
System.out.println(name);
System.out.println(s.getNumber());
System.out.println("-----------------");
//子類(lèi)調(diào)用自己特有的方法
s.method();?
}
}
4.3、Java中方法重寫(xiě)規(guī)則
子類(lèi)重寫(xiě)方法時(shí),在聲明前加@Override可檢測(cè)該方法是否為重寫(xiě)的方法
訪問(wèn)權(quán)限相同或子類(lèi)方法訪問(wèn)權(quán)限更大(訪問(wèn)權(quán)限順序public>默認(rèn))
class Fu{
void show(){}
public void method(){}
}
class Zi extends Fu{
public void show(){}? //編譯運(yùn)行沒(méi)問(wèn)題
void method(){}? ? ? //編譯錯(cuò)誤
}
方法名稱(chēng)必須相同
參數(shù)列表必須相同
返回值為基本類(lèi)型時(shí)必須相同
返回值為引用類(lèi)型時(shí)相同或子類(lèi)小(了解)
/*
* 方法重寫(xiě)的注意事項(xiàng)
*? 子類(lèi)重寫(xiě)方法時(shí),在聲明前加@Override可檢測(cè)該方法是否為重寫(xiě)的方法
*? 訪問(wèn)權(quán)限相同或子類(lèi)方法訪問(wèn)權(quán)限更大(訪問(wèn)權(quán)限順序public>默認(rèn))
*? 方法名稱(chēng)必須相同
*? 參數(shù)列表必須相同
*? 返回值為基本類(lèi)型時(shí)必須相同
*? 返回值為引用類(lèi)型時(shí)相同或子類(lèi)小(了解)
*/
public class Fu {
public void method(){
System.out.println(" 父類(lèi)方法");
}
public int sum(){
return 0;
}
public Person get(){
return null;
}
}
public class Zi extends Fu{
//訪問(wèn)權(quán)限相同或子類(lèi)方法訪問(wèn)權(quán)限更大(訪問(wèn)權(quán)限順序public>默認(rèn))
@Override
public void method(){
System.out.println("子類(lèi)方法");
}
//返回值為基本類(lèi)型時(shí)必須相同
@Override
public int sum(){
return 100;
}
//返回值為引用類(lèi)型時(shí)相同或子類(lèi)小(了解)
@Override
public Student get(){
return null;
}
}