繼承的由來
我們用代碼來引出繼承的由來堪滨。
定義一個貓(Cat)類胯陋,有name和color兩個屬性,有eat一個行為;
class Cat {
String name遏乔;//名字
String color义矛;//顏色
public void eat(){
System.out.println("吃東西");
}
}
然后定義一個狗(Dog)類,也有name和color兩個屬性盟萨,有eat一個行為凉翻;
class Dog {
String name;//名字
String color捻激;//顏色
public void eat(){
System.out.println("吃東西");
}
}
如上代碼制轰,我們很容易看出這么一個問題,cat和dog都有相同的name胞谭,color屬性艇挨,也同樣具有eat行為。同樣的代碼我們卻要寫兩次韭赘,那么有沒有一個方法缩滨,只聲明一次name,color屬性泉瞻,和eat行為呢脉漏。首先,貓和狗都屬于動物袖牙,都有name和color屬性侧巨,那么我們是否可以創(chuàng)建一個Animal類,讓它包含貓和狗嗎鞭达。繼承
的出現(xiàn)司忱,為我們解決了這個問題。
class Demo_Extends {
public static void main(String[] args) {
Cat c = new Cat();
c.color = "橘色";
c.name = "二喜";
c.eat();
System.out.println(c.name + "..." + c.color);
//運行結(jié)果為
//吃東西
//二喜...橘色
}
}
//定義一個Animal類
class Animal {
String color; //動物的顏色
String name; //動物的名字
public void eat() { //吃東西的功能
System.out.println("吃東西");
}
}
class Cat extends Animal {
}
class Dog extends Animal {
}
/*
extends是繼承的意思
Animal是父類
Cat和Dog都是子類
*/
綜上代碼我們發(fā)現(xiàn)畴蹭,我們定義了一個Animal類坦仍,含有color和name兩個屬性,一個eat行為叨襟。然后分別定義一個Cat和Dog類繁扎,并且集成自Animal類。我們在構(gòu)造函數(shù)中直接new一個Cat對象糊闽,然后直接給它的name和color屬性賦值梳玫,并調(diào)用eat行為,發(fā)現(xiàn)時可行的右犹。這樣提澎,我們就不用分別再為Cat和Dog聲明屬性和定義行為了。
繼承的好處和弊端
- A:繼承的好處
- a:提高了代碼的復用性(從上述例子可以看出)
- b:提高了代碼的維護性(比如為Cat和Dog添加一個leg屬性念链,只需要在Animal中添加即可)
- c:讓類與類之間產(chǎn)生了關(guān)系盼忌,是多態(tài)的前提
- B:繼承的弊端
類的耦合性增強了莉炉。(類與類之間的關(guān)聯(lián)太緊密,父類改變碴犬,子類也會相應的做出改變)
開發(fā)的原則:高內(nèi)聚,低耦合梆暮。
耦合:類與類的關(guān)系
內(nèi)聚:就是自己完成某件事情的能力
Java中類的繼承特點
- Java只支持單繼承服协,不支持多繼承。(一個兒子只能有一個爹)
//一個類只能有一個父類啦粹,不可以有多個父類偿荷。
class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//error
- 有些語言是支持多繼承,格式:extends 類1,類2,...
- Java支持多層繼承(繼承體系)
class A{}
class B extends A{}
class C extends B{}
- 如果想用這個體系的所有功能用最底層的類創(chuàng)建對象
看下面代碼示例
- 如果想看這個體系的共性功能,看最頂層的類
看下面代碼示例
class Demo_Extends {
public static void main(String[] args) {
//如果想用這個體系的所有功能用最底層的類創(chuàng)建對象
C c = new C();
c.age=11;
c.name="二喜"唠椭;
c.leg=4;
c.color="橘色"跳纳;
c.eat();
c.sleep();
c.run();
/*
c對象就包含了age,name贪嫂,leg寺庄,color屬性,以及eat力崇,sleep斗塘,run的行為
*/
//如果想看這個體系的共性功能,看最頂層的類
A a =new A();
a.age=2;
a.name="三毛";
a.eat();
/*
此時的a對象只包含age和name兩個屬性亮靴,以及eat一個行為馍盟。
*/
}
}
class A{
int age;
String name;
public void eat(){
System.out.printlb("吃東西");
}
}
class B extends A{
int leg;
public void sleep(){
System.out.printlb("睡覺");
}
}
class C extends B{
String color茧吊;
public void run(){
System.out.printlb("快跑");
}
}
繼承的注意事項
- a:子類只能繼承父類所有非私有的成員(成員方法和成員變量)
class Demo_Extends {
public static void main(String[] args) {
Son son =new Son();//聲明一個son對象
son.age=11;//這樣用是正確的
son.wife="王婆";//這樣用是錯誤的贞岭,因為wife是Father的私有變量
son.eat();//son具有eat的行為
son.sleep();//son不能訪問父類Father的私有方法sleep;這樣用是錯誤的
}
}
class Father {
int age搓侄;
private wife;
public void eat(){
System.out.println("我要吃飯");
}
private void sleep(){
System.out.print("我要去睡覺");
}
}
class Son entends Father {
}
- b:子類不能繼承父類的構(gòu)造方法瞄桨,但是可以通過super關(guān)鍵字去訪問父類構(gòu)造方法。
查看下方this和super關(guān)鍵字的使用
- c:不要為了部分功能而去繼承
項目經(jīng)理含有 姓名 工號 工資 獎金屬性讶踪;程序員 含有姓名 工號 工資讲婚,不要用為了相同的屬性去讓程序員集成項目經(jīng)理,或者項目經(jīng)理集成程序員俊柔。
什么時候使用繼承
- 繼承其實體現(xiàn)的是一種關(guān)系:"is a"筹麸。
(包含關(guān)系)
Person
?????Student
?????Teacher
水果
?????蘋果
?????香蕉
?????橘子
- 采用假設(shè)法。
如果有兩個類A,B雏婶。只有他們符合A是B的一種物赶,或者B是A的一種,就可以考慮使用繼承留晚。
繼承中成員變量的關(guān)系
- 子類中的成員變量和父類中的成員變量名稱不一樣,這個太簡單
- 子類中的成員變量和父類中的成員變量名稱一樣,這個怎么玩呢?
在子類方法中訪問一個變量的查找順序
a:在子類方法的局部范圍找,有就使用
b:在子類的成員范圍找,有就使用
c:在父類的成員范圍找,有就使用
d:如果還沒找到,就報錯
class Demo4_Extends {
public static void main(String[] args) {
Son s = new Son();
s.print();
}
}
/*
* A:案例演示
* a:不同名的變量
* b:同名的變量
子父類出現(xiàn)同名的變量只是在講課中舉例子有,在開發(fā)中是不會出現(xiàn)這種情況的
子類繼承父類就是為了使用父類的成員,那么如果定義了同名的成員變量沒有意義了
*/
class Father {
int num1 = 10;
int num2 = 30;
}
class Son extends Father {
int num2 = 20;
public void print() {
System.out.println(this.num1); //this既可以調(diào)用本類的,也可以調(diào)用父類的(本類沒有的情況下)
System.out.println(this.num2); //就近原則,子類有就不用父類的了
System.out.println(super.num2);
}
}
[注意]實際開發(fā)中不會遇到同名變量酵紫,自己在今后的開發(fā)過程中也不要給對象聲明相同名稱的變量
繼承中成員方法的關(guān)系
- 子類和父類的方法名不同告嘲,這個就無所謂了
- 子類中的方法和父類方法名不同
通過子類調(diào)用方法
1.先找子類中,看有沒有這個方法奖地,有就使用
2.再看父類中有沒有這個方法橄唬,有就使用
3.如果都沒有,俺么就報錯
this和super的區(qū)別和應用
- A:this和super都代表什么
- this:代表當前對象的引用,誰來調(diào)用我,我就代表誰
- super:代表當前對象父類的引用
- B:this和super的使用區(qū)別
- a:調(diào)用成員變量
- this.成員變量 調(diào)用本類的成員變量,也可以調(diào)用父類的成員變量
- super.成員變量 調(diào)用父類的成員變量
- b:調(diào)用構(gòu)造方法
- this(...) 調(diào)用本類的構(gòu)造方法
- super(...) 調(diào)用父類的構(gòu)造方法
- c:調(diào)用成員方法
- this.成員方法 調(diào)用本類的成員方法,也可以調(diào)用父類的方法
- super.成員方法 調(diào)用父類的成員方法
- a:調(diào)用成員變量
繼承中構(gòu)造方法的關(guān)系
子類中所有的構(gòu)造方法默認都會訪問父類中空參數(shù)的構(gòu)造方法
因為子類會繼承父類中的數(shù)據(jù)参歹,可能還會使用父類的數(shù)據(jù)仰楚。
,子類初始化之前犬庇,一定要先完成父類數(shù)據(jù)的初始化僧界。
每一個構(gòu)造方法的第一條語句默認都是:super() Object類最頂層的父類。
class Demo5_Extends {
public static void main(String[] args) {
Son s = new Son();
}
}
/*
*
* 子類中所有的構(gòu)造方法默認都會訪問父類中空參數(shù)的構(gòu)造方法
* 因為子類會繼承父類中的數(shù)據(jù)臭挽,可能還會使用父類的數(shù)據(jù)捂襟。
* 所以,子類初始化之前欢峰,一定要先完成父類數(shù)據(jù)的初始化葬荷。
* 每一個構(gòu)造方法的第一條語句默認都是:super() Object類最頂層的父類。
*/
class Father extends Object {
public Father() {
super();
System.out.println("Father 的構(gòu)造方法");
}
}
class Son extends Father {
public Son() {
super(); //這是一條語句,如果不寫,系統(tǒng)會默認加上,用來訪問父類中的空參構(gòu)造
System.out.println("Son 的構(gòu)造方法");
}
}
繼承中構(gòu)造方法的注意事項
-
父類沒有無參構(gòu)造方法,子類怎么辦?
- super解決
- this解決
super(…)或者this(….)必須出現(xiàn)在構(gòu)造方法的第一條語句上
class Demo6_Extends {
public static void main(String[] args) {
Son s1 = new Son();
System.out.println(s1.getName() + "..." + s1.getAge());
System.out.println("--------------------");
Son s2 = new Son("張三",23);
System.out.println(s2.getName() + "..." + s2.getAge());
}
}
class Father {
private String name; //姓名
private int age; //年齡
public Father() { //空參構(gòu)造
System.out.println("Father 空參構(gòu)造");
}
public Father(String name,int age) { //有參構(gòu)造
this.name = name;
this.age = age;
System.out.println("Father 有參構(gòu)造");
}
public void setName(String name) { //設(shè)置姓名
this.name = name;
}
public String getName() { //獲取姓名
return name;
}
public void setAge(int age) { //設(shè)置年齡
this.age = age;
}
public int getAge() { //獲取年齡
return age;
}
}
class Son extends Father {
public Son() { //空參構(gòu)造
this("王五",25); //本類中的構(gòu)造方法
//super("李四",24); //調(diào)用父類中的構(gòu)造方法
System.out.println("Son 空參構(gòu)造");
}
public Son(String name,int age) { //有參構(gòu)造
super(name,age);
System.out.println("Son 有參構(gòu)造");
}
}