Java之繼承和抽象類


繼承

繼承的實現

繼承通過extends實現
格式:class 子類 extends 父類 { }
舉例:class Dog extends Animal { }
 
繼承帶來的好處
繼承可以讓類與類之間產生關系,子父類關系,產生子父類后,子類則可以使用父類中非私有的成員。
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中繼承的特點

1. Java中類只支持單繼承,不支持多繼承
錯誤范例:class A extends B, C { }
2. 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方法
}            

繼承中的成員訪問特點

繼承中變量的訪問特點

在子類方法中訪問一個變量,采用的是就近原則。

  1. 子類局部范圍找
  2. 子類成員范圍找
  3. 父類成員范圍找
  4. 如果都沒有就報錯(不考慮父親的父親…)
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()

問題:如果父類中沒有無參構造方法,只有帶參構造方法,該怎么辦呢?

1. 通過使用super關鍵字去顯示的調用父類的帶參構造方法
2. 子類通過this去調用本類的其他構造方法,本類其他構造方法再通過super去手動調用父類的帶參的構造方法
注意: this(…)super(…) 必須放在構造方法的第一行有效語句,並且二者不能共存

繼承中成員方法的訪問特點

通過子類對象訪問一個方法
1. 子類成員范圍找
2. 父類成員范圍找
3. 如果都沒有就報錯(不考慮父親的父親…)

方法重寫

1、方法重寫概念
子類出現了和父類中一模一樣的方法聲明(方法名一樣,參數列表也必須一樣)
 
2、方法重寫的應用場景
當子類需要父類的功能,而功能主體子類有自己特有內容時,可以重寫父類中的方法,這樣,即沿襲了 父類的功能,又定義了子類特有的內容
 
3、Override注解
用來檢測當前的方法,是否是重寫的方法,起到【校驗】的作用

方法重寫的注意事項

1. 私有方法不能被重寫(父類私有成員子類是不能繼承的)
2. 子類方法訪問權限不能更低(public > 默認 > 私有)
3. 靜態方法不能被重寫,如果子類也有相同的方法,並不是重寫的父類的方法,是將父類的方法隱藏
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中,一個沒有方法體的方法應該定義為抽象方法,而類中如果有抽象方法,該類必須定義為抽象類!

抽象類的特點

抽象類和抽象方法必須使用 abstract 關鍵字修飾 
//抽象類的定義
public abstract class 類 名 {} //抽象方法的定義
public abstract void eat();
抽象類中不一定有抽象方法,有抽象方法的類一定是抽象類
抽象類不能實例化
抽象類可以有構造方法
抽象類的子類, 要么重寫抽象類中的所有抽象方法, 要么是自己變成抽象類 

抽象類的案例

案例需求
定義貓類(Cat)和狗類(Dog)
貓類成員方法:eat(貓吃魚)drink(喝水…)
狗類成員方法:eat(狗吃肉)drink(喝水…)
實現步驟
1. 貓類和狗類中存在共性內容,應向上抽取出一個動物類(Animal)
2. 父類Animal中,無法將 eat 方法具體實現描述清楚,所以定義為抽象方法
3. 抽象方法需要存活在抽象類中,將Animal定義為抽象類
4. 讓 Cat 和 Dog 分別繼承 Animal,重寫eat方法
5. 測試類中創建 Cat 和 Dog 對象,調用方法測試 
 

動物類

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); // 正 確
}

代碼塊 

代碼塊概述

在Java中,使用 { } 括起來的代碼被稱為代碼塊 

代碼塊分類

局部代碼塊
位置: 方法中定義
作用: 限定變量的生命周期,及早釋放,提高內存利用率
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類的帶參數構造方法
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM