繼承
繼承的實現
public class Fu {
public void show() { System.out.println("show方法被調用"); } } public class Zi extends Fu { public void method() { System.out.println("method方法被調用"); } } public class Demo { public static void main(String[] args) { //創建對象,調用方法
Fu f = new Fu(); f.show(); Zi z = new Zi(); z.method(); z.show(); } }
繼承的好處和弊端
繼承好處
提高了代碼的復用性(多個類相同的成員可以放到同一個類中) 提高了代碼的維護性(如果方法的代碼需要修改,修改一處即可)繼承弊端
繼承讓類與類之間產生了關系,類的耦合性增強了,當父類發生變化時子類實現也不得不跟着變化,削弱了子類的獨立性
繼承的應用場景:
使用繼承,需要考慮類與類之間是否存在is..a的關系,不能盲目使用繼承is..a的關系:誰是誰的一種,例如:老師和學生是人的一種,那人就是父類,學生和老師就是子類
Java中繼承的特點
public class Granddad { public void drink() { System.out.println("爺爺愛喝酒"); } } public class Father extends Granddad { public void smoke() { System.out.println("爸爸愛抽煙"); } } public class Mother { public void dance() { System.out.println("媽媽愛跳舞"); } } public class Son extends Father { // 此時,Son類中就同時擁有drink方法以及smoke方法
}
繼承中的成員訪問特點
繼承中變量的訪問特點
在子類方法中訪問一個變量,采用的是就近原則。
- 子類局部范圍找
- 子類成員范圍找
- 父類成員范圍找
- 如果都沒有就報錯(不考慮父親的父親…)
class Fu { int num = 10; } class Zi { int num = 20; public void show(){ int num = 30; System.out.println(num); } } public class Demo1 { public static void main(String[] args) { Zi z = new Zi(); z.show(); // 輸出show方法中的局部變量30
} }
super
this&super關鍵字:
this:代表本類對象的引用
super:代表父類存儲空間的標識(可以理解為父類對象引用)
this和super的使用分別成員變量:
this.成員變量 - 訪問本類成員變量
super.成員變量 - 訪問父類成員變量
成員方法:
this.成員方法 - 訪問本類成員方法
super.成員方法 - 訪問父類成員方法
構造方法:
this(…) - 訪問本類構造方法
super(…) - 訪問父類構造方法
繼承中構造方法的訪問特點
注意:子類中所有的構造方法默認都會訪問父類中無參的構造方法
子類會繼承父類中的數據,可能還會使用父類的數據。所以,子類初始化之前,一定要先完成父類數據的初始化, 原因在於,每一個子類構造方法的第一條語句默認都是:super()
問題:如果父類中沒有無參構造方法,只有帶參構造方法,該怎么辦呢?
繼承中成員方法的訪問特點
方法重寫
方法重寫的注意事項
public class Fu { private void show() { System.out.println("Fu中show()方法被調用"); } void method() { System.out.println("Fu中method()方法被調用"); } } public class Zi extends Fu { /* 編譯【出錯】,子類不能重寫父類私有的方法*/ @Override private void show() { System.out.println("Zi中show()方法被調用"); } /* 編譯【出錯】,子類重寫父類方法的時候,訪問權限需要大於等於父類 */ @Override private void method() { System.out.println("Zi中method()方法被調用"); } /* 編譯【通過】,子類重寫父類方法的時候,訪問權限需要大於等於父類 */ @Override public void method() { System.out.println("Zi中method()方法被調用"); } }
權限修飾符
super內存圖
對象在堆內存中,會單獨存在一塊super區域,用來存放父類的數據(父類的空參構造函數必須寫)
父類沒有空參構造
1.在子類通過super調用父類有參構造函數
public Child(int age){ super(age); this.age=age; System.out.println("Child parameter constructor called"); }
2.子類通過this調用本類其他構造方法,本類其他構造方法再通過調用super去手動調用父類有參構造方法
public Child(){ this(10); System.out.println("Child non_parameter constructor called"); } public Child(int age){ super(age); System.out.println("Child parameter constructor called"); }
注意this和super都必須放在構造方法第一行才能作為有效語句,並且二者不能共存
抽象類
抽象類的概述
當我們在做子類共性功能抽取時,有些方法在父類中並沒有具體的體現,這個時候就需要抽象類了!
在Java中,一個沒有方法體的方法應該定義為抽象方法,而類中如果有抽象方法,該類必須定義為抽象類!
抽象類的特點
//抽象類的定義
public abstract class 類 名 {} //抽象方法的定義
public abstract void eat();
抽象類的案例
動物類
public abstract class Animal { public void drink(){ System.out.println("喝水"); } public Animal(){ } public abstract void eat(); }
貓類
public class Cat extends Animal { @Override public void eat() { System.out.println("貓吃魚"); } }
狗類
public class Dog extends Animal { @Override public void eat() { System.out.println("狗吃肉"); } }
測試類
public static void main(String[] args) { Dog d = new Dog(); d.eat(); d.drink(); Cat c = new Cat(); c.drink(); c.eat(); //Animal a = new Animal(); //抽象類不能實例話對象 //a.eat();
}
模板設計模式
設計模式
設計模式(Design pattern)是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性、程序的重用性。
模板設計模式
把抽象類整體就可以看做成一個模板,模板中不能決定的東西定義成抽象方法 讓使用模板的類(繼承抽象類的類)去重寫抽象方法實現需求
模板設計模式的優勢
模板已經定義了通用結構,使用者只需要關心自己需要實現的功能即可
示例代碼
模板類
/* 作文模板類 */
public abstract class CompositionTemplate { public final void write(){ System.out.println("<<我的爸爸>>"); body(); System.out.println("啊~ 這就是我的爸爸"); } public abstract void body(); }
實現類A
public class Tom extends CompositionTemplate { @Override public void body() { System.out.println("那是一個秋天, 風兒那么纏綿,記憶中, " +
"那天爸爸騎車接我放學回家,我的腳卡在了自行車鏈當中, 爸爸蹬不動,他就
站起來蹬...");
} }
測試類
public class Test { public static void main(String[] args) { Tom t = new Tom(); t.write(); } }
final
fianl關鍵字的作用
final代表最終的意思,可以修飾成員方法,成員變量,類final修飾類、方法、變量的效果
fianl修飾類:該類不能被繼承(不能有子類,但是可以有父類)
public final class Parent{};
final修飾方法:該方法不能被重寫
public final void show{};
final修飾變量:表明該變量是一個常量,不能再次賦值。變量是基本類型,不能改變值
final int a=10; //正確
a=20; //錯誤
變量是引用類型,不能改變的是地址值,但地址里面的內容是可以改變的
public static void main(String[] args){ final Student s = new Student(23); s = new Student(24); // 錯 誤
s.setAge(24); // 正 確
}
代碼塊
代碼塊概述
代碼塊分類
public class Test { /* 局部代碼塊 位置:方法中定義 作用:限定變量的生命周期,及早釋放,提高內存利用率 */
public static void main(String[] args) { { int a = 10; System.out.println(a); } // System.out.println(a);
} }
構造代碼塊
位置: 類中方法外定義
特點: 每次構造方法執行的時,都會執行該代碼塊中的代碼,並且在構造方法執行前執行作用: 將多個構造方法中相同的代碼,抽取到構造代碼塊中,提高代碼的復用性
public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student(10);
}
class Student { { System.out.println("好好學習"); } public Student(){ System.out.println("空參數構造方法"); } public Student(int a){ System.out.println("帶參數構造方法"); } }
輸出:
好好學習
空參數構造方法
好好學習
帶參數構造方法
靜態代碼塊
位置: 類中方法外定義
特點: 需要通過static關鍵字修飾,隨着類的加載而加載,並且只執行一次作用: 在類加載的時候做一些數據初始化的操作
public static void main(String[] args) { Person p1 = new Person(); Person p2 = new Person(10); } class Person { static { System.out.println("我是靜態代碼塊, 我執行了"); } public Person(){ System.out.println("我是Person類的空參數構造方法"); } public Person(int a){ System.out.println("我是Person類的帶參數構造方法"); } }
輸出:
我是靜態代碼塊, 我執行了
我是Person類的空參數構造方法
我是Person類的帶參數構造方法