提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
文章目錄
- 前言
- 一、繼承的概念和使用細則
- 1.1 繼承的基本使用和含義
- 1.2 關于子類訪問父類成員的問題
- 1.3 super關鍵的引出
- 1.4 super調用父類當中指定的構造方法
- 1.5 關于super和this
- 1.6 繼承關系上的代碼塊執行順序
- 1.7 訪問修飾限定符-protected關鍵字
- 1.8 java中的繼承方式
- 1.9 final關鍵字
- 二、繼承和組合
- 總結
前言
提示:這里可以添加本文要記錄的大概內容:
繼承作為面向對象編程的核心支柱,通過對類之間共性的高效抽取實現代碼復用,為構建層次化、可擴展的軟件系統奠定堅實基礎。
提示:以下是本篇文章正文內容,下面案例可供參考
一、繼承的概念和使用細則
1.1 繼承的基本使用和含義
繼承(inheritance)機制:是?向對象程序設計使代碼可以復?的最重要的?段,它允許程序員在保持原有類特性的基礎上進?擴展,增加新功能,這樣產?新的類,稱派?類。
繼承的目的就是對不同類之間進行共性的抽取,從而來實現代碼的復用!!!!!!
被繼承的類稱為父類、基類和超類,繼承別人的類稱為子類和派生類,和生活中的情形很接近所以很好理解。
在代碼中,繼承最大的特性就是子類可以繼承父類當中的成員變量和成員方法!!
接下來對上述圖示中的類之間的關系,利用繼承用代碼進行實現。
package com.dzj;public class Animal {public String name;public int age;public float weight;public void eat(){System.out.println(name+"---吃東西---");}public void sleep(){System.out.println(name+"開始睡覺~~~~~");}
}
package com.dzj;public class Cat extends Animal{public void mew(){System.out.println(name+"喵喵喵");}
}
package com.dzj;public class Dog extends Animal{public void bark(){System.out.println(this.name+"狗叫");}
}
package com.dzj;public class TestExtend {public static void main(String[] args) {Cat cat=new Cat();cat.name="hzp";cat.eat();cat.sleep();cat.mew();Dog dog=new Dog();dog.name="xxx";dog.eat();dog.sleep();dog.bark();}
}
1.2 關于子類訪問父類成員的問題
關于這個問題,只要遵循一個就近原則即可:如果子類有優先訪問子類的,子類沒有的再去父類找!!!!
子類和父類不存在同名成員變量
package com.demo1;public class Base {int a=10;int b=20;
}
package com.demo1;public class Derived extends Base{int c=30;public void method(){System.out.println(a);System.out.println(b);System.out.println(c);}
}
package com.demo1;public class Test {public static void main(String[] args) {Derived derived=new Derived();derived.method();}
}
結果表明,如果子類和父類不存在同名的成員變量,子類可以直接訪問父類的成員變量。
如果子類和父類存在同名成員變量:
package com.demo1;public class Base {int a=10;int b=20;
}
package com.demo1;public class Derived extends Base{int a=100;int b=200;int c=30;public void method(){System.out.println(a);System.out.println(b);System.out.println(c);}
}
package com.demo1;public class Test {public static void main(String[] args) {Derived derived=new Derived();derived.method();}
}
結果表明,如果父子類出現同名的成員變量,優先使用子類的成員變量,即遵循就近原則。
對于子類訪問父類的成員方法其實原理比較類似,接下來直接上代碼解釋:
package com.demo1;public class Base {int a=10;int b=20;public void methodA(){System.out.println("Base的methodA--------");}public void methodB(int x){System.out.println("Base的methodA--------");System.out.println(x);}
}
package com.demo1;public class Derived extends Base{int a = 100;int b = 200;int c = 30;public void method(){System.out.println(a);System.out.println(b);System.out.println(c);}public void methodA(){System.out.println("Derived的methodA--------");}public void methodB(){System.out.println("Derived的mmethodB--------");}public void methodC(){System.out.println("Derived的methodC--------");}
}
package com.demo1;public class Test {public static void main(String[] args) {Derived derived=new Derived();derived.methodA();derived.methodB();derived.methodB(100);derived.methodC();}
}
從結果可以看出整個調用過程還是遵循就近原則的,唯一需要注意的是成員方法本身是支持重載的,如果存在方法的重載根據所給參數的不同來確定最后調用的是哪一個成員方法。
1.3 super關鍵的引出
問題:如果?類中存在與?類中相同的成員時,那如何在?類中訪問?類相同名稱的成員呢?,也就是說如果存在同名的情況,我一定要訪問父類的成員變量和成員方法怎么做???
答案就是利用super關鍵字,接下來將用代碼進行演示super關鍵的作用,最后在做一個小的總結。
package com.demo1;public class Base {int a=10;int b=20;public void methodA(){System.out.println("Base的methodA--------");}public void methodB(int x){System.out.println("Base的methodA--------");System.out.println(x);}
}
package com.demo1;public class Derived extends Base{int a = 100;int b = 200;int c = 30;public void method(){System.out.println(a);System.out.println(b);System.out.println(c);System.out.println(super.a);System.out.println(super.b);super.methodA();}public void methodA(){System.out.println("Derived的methodA--------");}public void methodB(){System.out.println("Derived的mmethodB--------");}public void methodC(){System.out.println("Derived的methodC--------");}
}
package com.demo1;public class Test {public static void main(String[] args) {Derived derived=new Derived();/*derived.methodA();derived.methodB();derived.methodB(100);derived.methodC();*/derived.method();}
}
從結果可以看出,在子類成員方法中可以使用super關鍵字訪問父類的成員變量和成員方法
注意事項
**1. 只能在非靜態?法中使用(和this關鍵字一樣)
- 在?類?法中,訪問?類的成員變量和?法。**
1.4 super調用父類當中指定的構造方法
package com.demo2;public class Base {public Base(int x){System.out.println("Base構造方法");System.out.println(x+"----"+x);}
}
package com.demo2;public class Derived extends Base{public Derived() {System.out.println("Derived構造方法");}
}
package com.demo2;import com.demo1.Derived;public class Test {public static void main(String[] args) {Derived derived=new Derived();}}
上述結果表明Base構造方法缺少參數,出現錯誤的原因就是,在構建子類對象的同時,要先完成父類的構造函數初始化在完成子類構造函數的初始化!
public class Derived extends Base{public Derived() {super(100);System.out.println("Derived構造方法");}
}
稍作修改就可以編譯成功!
【注意事項】
? 通過super(參數)的形式可以調??類指定的構造?法
? super()的形式只能出現在?類的構造?法當中且必須在第??
再思考一個問題:先看如下代碼
package com.demo2;public class Base {public Base(){System.out.println("Base構造方法");/*System.out.println(x+"----"+x);*/}
}
package com.demo2;public class Derived extends Base{public Derived() {/*super(100);*/System.out.println("Derived構造方法");}
}
package com.demo2;import com.demo2.Derived;public class Test {public static void main(String[] args) {Derived derived=new Derived();}
}
代碼可以正常運行!!!為什么這里沒用super也能跑,因為再子類構造方法的第一行系統默認會加上一個super()調用父類無參構造方法。僅限?類的構造?法是不帶參數的構造?法且只有這?個的情況下。
另外補充一點,super()和this()是不能一起使用的!!!,因為他們都要求放在構造函數第一行上
1.5 關于super和this
【相同點】
1. 都是Java中的關鍵字
2. 只能在類的?靜態?法中使?,?來訪問?靜態成員?法和字段
3. 在構造?法中調?時,必須是構造?法中的第?條語句,并且不能同時存在
【不同點】
1. this是當前對象的引?,當前對象即調?實例?法的對象,super相當于是?類對象中從?類繼承下
來部分成員的引?
從圖中可以看出,super和this指向的是不同的空間。
2. 在?靜態成員?法中,this?來訪問本類的?法和屬性,super?來訪問?類繼承下來的?法和屬性
4. 在構造?法中:this(…)?于調?本類構造?法,super(…)?于調??類構造?法,兩種調?不能同時在構造?法中出現
5. 構造?法中?定會存在super(…)的調?,??沒有寫編譯器也會增加,但是this(…)??不寫則沒有
1.6 繼承關系上的代碼塊執行順序
package com.demo3;
public class Person {String name;int age;public Person(String name,int age){this.name=name;this.age=age;System.out.println("Person:構造方法執行");}{System.out.println("Person:實例代碼塊執行");}static{System.out.println("Person:靜態代碼塊執行");}
}
package com.demo3;public class Student extends Person{
public Student(String name,int age){super(name,age);System.out.println("Student:構造方法執行");
}{System.out.println("Student:實例代碼塊執行");}static{System.out.println("Student:靜態代碼塊執行");}
}
package com.demo3;public class Test {public static void main(String[] args) {Student student1=new Student("dzj",18);System.out.println("--------------------");Student student2=new Student("dzj",18);}
}
通過分析執?結果,得出以下結論:
1. ?類靜態代碼塊優先于?類靜態代碼塊執?,且是最早執?。
2. ?類實例代碼塊和?類構造?法緊接著執?。
3. ?類的實例代碼塊和?類構造?法緊接著再執?。
4. 第?次實例化?類對象時,?類和?類的靜態代碼塊都將不會再執?
1.7 訪問修飾限定符-protected關鍵字
如果被protected 關鍵字修飾該類當中成員變量,成員?法等表?要么只能在同?個包中的類中進?訪問,要么在不同包中只能通過在繼承關系上的?類對象來訪問
package com.demo2;public class Base {/* public Base(){System.out.println("Base構造方法");*//*System.out.println(x+"----"+x);*//*}*/protected int x=100;
}
package com.demo3;import com.demo2.Base;public class Derived extends Base {public static void main(String[] args) {Derived derived=new Derived();System.out.println(derived.x);}
}
打印結果表明:不同包下的子類可以訪問父類中被protected修飾的成員變量.
特殊情況:
package com.demo3;import com.demo2.Base;
class C extends Base{public static void main(String[] args) {C c=new C();System.out.println(c.x);}
}public class Derived extends Base {public static void main(String[] args) {Derived derived=new Derived();System.out.println(derived.x);C c=new C();System.out.println(c.x);}
}
雖然Derived 類繼承?Base 類,但它不能訪問其他 Base 類?類(這?是C類)實例的protected 成員。可能感覺比較抽象,一個簡單的理解就是要訪問protected修飾的變量,那么只能在本類中用自己的對象去訪問,不能用別人的,所以個人認為這個protected的訪問有比較大的局限性。
總結:
如果在情況允許下,能用private就用private,這樣能最大程度的保持封裝性,因此我們在使?的時候應該盡可能的使??較嚴格的訪問權限。
1.8 java中的繼承方式
java中不允許多繼承的存在,?般我們不希望出現超過三層的繼承關系
1.9 final關鍵字
public class Test_final {public static void main(String[] args) {final int a=10;a=20;}
}
final修飾變量即為常量,不可以發生改變
public final class Animal {
}
public class Bird extends Animal{}
final修飾類即為不可繼承
final修飾方法即為該方法不可以被重寫,這一點再后續的博客中再講解。
二、繼承和組合
繼承表?對象之間是is-a的關系,?如:狗是動物,貓是動物
組合表?對象之間是has-a的關系,?如:汽?
用代碼來解釋更清楚:
package com.demo4;public class Car {private Tire tire;private Engine engine;public Tire getTire() {return tire;}public void setTire(Tire tire) {this.tire = tire;}public Engine getEngine() {return engine;}public void setEngine(Engine engine) {this.engine = engine;}
}
package com.demo4;public class Engine {int size;
}
package com.demo4;public class Tire {String color;
}
package com.demo4;public class Benz extends Car{public static void main(String[] args) {Benz benz =new Benz();Tire tire=new Tire();Engine engine=new Engine();engine.size=100;tire.color="黑色";benz.setTire(tire);benz.setEngine(engine);System.out.println(benz.getEngine().size);System.out.println(benz.getTire().color);}}
組合和繼承都可以實現代碼復?,應該使?繼承還是組合,需要根據應?場景來選擇,?般建議:能?組合盡量?組合,繼承層次太深的代碼不利于維護。
總結
從基礎使用到訪問控制,從super關鍵字到代碼塊執行順序,深入理解繼承機制能顯著提升代碼復用性和可維護性,但需警惕過度繼承帶來的設計復雜性,合理運用final和組合優化架構。