[Java]抽象類

1. 什么是抽象類?

1.1 定義:

抽象類是一個不能實例化的類,它是用來作為其他類的基類的。抽象類可以包含抽象方法和非抽象方法。抽象方法沒有方法體,子類必須重寫這些方法并提供具體的實現。抽象類可以有構造方法、成員變量、靜態方法和默認方法等。

1.2 特點:

  • 抽象類不能實例化,即不能創建抽象類的對象
  • 抽象類可以有抽象方法和非抽象方法
  • 子類必須實現抽象類中的所有抽象方法,除非子類本身是抽象類。

2. 抽象類的聲明

在Java中,使用abstract關鍵字來聲明抽象類和抽象方法。

abstract class Animal {// 抽象方法abstract void sound();// 非抽象方法(普通方法)void eat() {System.out.println("Animal is eating");}
}

3. 抽象類與繼承

3.1 解釋:

子類繼承抽象類時,必須實現抽象類中的所有抽象方法,除非子類也是抽象類。如果子類沒有實現抽象類的所有抽象方法,子類也必須被聲明為抽象類。

3.2 示例:

abstract class Animal {abstract void sound();  // 抽象方法
}class Dog extends Animal {@Overridevoid sound() {System.out.println("Dog barks");}
}class Cat extends Animal {@Overridevoid sound() {System.out.println("Cat meows");}
}

在這個例子中,DogCat類分別實現了Animal類中的抽象方法sound

4. 抽象類的構造方法

4.1 解釋:

抽象類可以有構造方法,構造方法在子類創建對象時被調用。雖然不能直接實例化抽象類,但可以通過子類的構造方法來調用父類的構造方法。

4.2 示例:

abstract class Animal {Animal() {System.out.println("Animal constructor");}abstract void sound();
}class Dog extends Animal {Dog() {super();  // 調用父類的構造方法System.out.println("Dog constructor");}@Overridevoid sound() {System.out.println("Dog barks");}
}class abstract_Main{public static void main(String args[]){Animal dog = new Dog();dog.sound();}}

輸出:

Animal constructor
Dog constructor
Dog barks

5. 抽象類的成員變量

5.1 解釋:

抽象類可以包含成員變量,它們可以是privateprotectedpublic等不同的訪問修飾符。成員變量可以在抽象類中進行初始化,也可以在子類中進行修改。

5.2 示例:

abstract class Animal {String name;  // 成員變量Animal(String name) {this.name = name;}abstract void sound();
}class Dog extends Animal {Dog(String name) {super(name);  // 調用父類構造方法}@Overridevoid sound() {System.out.println(name + " barks");}
}

6. 抽象類的訪問修飾符

6.1 解釋:

抽象類的訪問修飾符(如publicprotected等)與普通類相同。可以根據需要控制訪問級別,確保只有適當的類可以訪問抽象類。

6.2 示例:

abstract class Animal {abstract void sound();
}public class Main {public static void main(String[] args) {// Animal animal = new Animal();  // 錯誤:不能實例化抽象類Dog dog = new Dog();dog.sound();  // 輸出:Dog barks}
}class Dog extends Animal {@Overridevoid sound() {System.out.println("Dog barks");}
}

7. 抽象類與接口的區別

7.1 區別:

抽象類和接口都可以用來定義類的行為規范,但它們有一些關鍵的區別:

特性抽象類接口
是否可以有方法體可以有抽象方法和非抽象方法只能有抽象方法(Java 8之后,可以有默認方法和靜態方法)
是否可以有成員變量可以有成員變量不可以有成員變量
是否支持多繼承只能繼承一個類可以實現多個接口
構造方法可以有構造方法沒有構造方法
繼承的限制只能繼承一個抽象類可以實現多個接口

7.2 選擇使用抽象類還是接口:

  • 抽象類:適用于類之間有“是一個”關系且需要共享代碼的情況。比如,多個類共享一些通用的屬性和方法時,可以使用抽象類。
  • 接口:適用于不同類之間有“行為”上的共性時。接口更強調行為規范的定義,可以在多個不相關的類中實現。

8. 抽象類的多態

8.1 解釋:

和其他類一樣,抽象類也支持多態。當父類類型的引用指向子類對象時,可以調用子類的重寫方法。這使得抽象類可以與子類一起使用,支持多態特性。

8.2 示例:

abstract class Animal {abstract void sound();
}class Dog extends Animal {@Overridevoid sound() {System.out.println("Dog barks");}
}class Cat extends Animal {@Overridevoid sound() {System.out.println("Cat meows");}
}public class Main {public static void main(String[] args) {Animal animal1 = new Dog();Animal animal2 = new Cat();animal1.sound();  // 輸出:Dog barksanimal2.sound();  // 輸出:Cat meows}
}

通過多態,Animal引用可以指向不同的子類對象,并調用子類的sound方法。

9. 抽象類的局限性

盡管抽象類具有許多優勢,但它也有一些局限性:

  • 只能繼承一個抽象類:Java中不支持多重繼承,因此如果一個類繼承了某個抽象類,它就不能再繼承其他類。這可能會在設計中造成一些限制。
  • 不能實例化抽象類不能直接實例化,因此必須通過子類來實例化。

10. 抽象類的應用場景

10.1 抽象類通常用于以下情況:

  • 提供模板方法:通過在抽象類中定義一個具體的框架方法,然后讓具體的子類提供實現細節。比如,常見的模板方法模式就是用抽象類實現的。
  • 共享代碼:如果多個類有相似的功能,可以將這些功能放在抽象類中,由子類繼承。
  • 多態支持:通過抽象類和繼承機制,支持多態,讓同一類型的對象能夠表現出不同的行為。

10.2 示例:模板方法模式

// 抽象類,定義了模板方法
abstract class Template {// 模板方法,定義了執行步驟的順序public final void execute() {step1();step2();step3();}// 步驟1(抽象方法,由具體子類實現)abstract void step1();// 步驟2(抽象方法,由具體子類實現)abstract void step2();// 步驟3(具體方法,子類可以直接使用)void step3() {System.out.println("Step 3: Common step");}
}// 具體類A,實現了模板方法中定義的步驟
class ConcreteClassA extends Template {@Overridevoid step1() {System.out.println("ConcreteClassA: Step 1");}@Overridevoid step2() {System.out.println("ConcreteClassA: Step 2");}
}// 具體類B,實現了模板方法中定義的步驟
class ConcreteClassB extends Template {@Overridevoid step1() {System.out.println("ConcreteClassB: Step 1");}@Overridevoid step2() {System.out.println("ConcreteClassB: Step 2");}
}public class Main {public static void main(String[] args) {// 使用ConcreteClassA來執行模板方法Template classA = new ConcreteClassA();System.out.println("Executing Template in ConcreteClassA:");classA.execute();  // 調用模板方法System.out.println("\n-------------------");// 使用ConcreteClassB來執行模板方法Template classB = new ConcreteClassB();System.out.println("Executing Template in ConcreteClassB:");classB.execute();  // 調用模板方法}
}

輸出:

Executing Template in ConcreteClassA:
ConcreteClassA: Step 1
ConcreteClassA: Step 2
Step 3: Common step-------------------Executing Template in ConcreteClassB:
ConcreteClassB: Step 1
ConcreteClassB: Step 2
Step 3: Common step

?解釋:

  1. Template

    • 這個類定義了一個模板方法 execute(),它規定了執行步驟的順序:step1()step2()step3()
    • step1()step2() 是抽象方法,要求具體子類去實現它們。
    • step3() 是一個具體方法,所有子類都可以直接使用,子類不需要重寫。
  2. ConcreteClassAConcreteClassB

    • 這兩個類都繼承了 Template 類,并實現了 step1()step2() 方法,但它們的具體實現是不同的。
    • step3() 由父類 Template 提供,不需要在子類中實現。
  3. 模板方法的使用

    • Main 類的 main() 方法中,我們創建了 ConcreteClassAConcreteClassB 的實例,并調用了它們的 execute() 方法。
    • 每次調用 execute() 方法時,都會執行 Template 中定義的步驟順序,但實際執行的內容是由 ConcreteClassAConcreteClassB 提供的 step1()step2() 方法。

11. 抽象類與接口的結合使用

11.1解釋:

在Java中,抽象類和接口可以結合使用,一個類可以同時實現接口并繼承抽象類。這可以讓你充分利用接口的多繼承特性,同時還能通過抽象類共享代碼。

11.2 示例:

// 定義Animal接口,要求實現sound方法
interface Animal {void sound();  // 聲明發出聲音的方法
}// 定義Mammal抽象類,繼承自Animal接口
abstract class Mammal implements Animal {// 聲明抽象方法walk,表示哺乳動物的步態abstract void walk();
}// Dog類繼承自Mammal,并實現sound和walk方法
class Dog extends Mammal {// 實現Animal接口的sound方法@Overridepublic void sound() {System.out.println("Dog barks");}// 實現Mammal類的walk方法@Overridevoid walk() {System.out.println("Dog walks on four legs");}
}// 主類,用于測試Dog類的功能
public class Main {public static void main(String[] args) {// 創建一個Dog對象Dog dog = new Dog();// 調用Dog類的sound方法dog.sound();  // 輸出:Dog barks// 調用Dog類的walk方法dog.walk();   // 輸出:Dog walks on four legs}
}

解釋:

  1. Animal 接口

    • Animal 接口聲明了一個方法 sound(),所有實現了 Animal 接口的類必須提供對該方法的具體實現。
  2. Mammal 抽象類

    • Mammal 是一個抽象類,它實現了 Animal 接口,但并沒有提供 sound() 方法的實現,子類 Dog 需要提供該方法的實現。
    • Mammal 類中還聲明了一個抽象方法 walk(),表示哺乳動物的行走方式。具體的 walk() 方法由子類實現。
  3. Dog

    • Dog 類繼承自 Mammal,并實現了 sound()walk() 方法,具體定義了狗的行為:叫聲和走路方式。
  4. Main

    • Main 類創建了 Dog 類的實例,并調用了 sound()walk() 方法,輸出狗的行為。

12. 抽象類中的靜態方法

12.1 解釋:

抽象類也可以包含靜態方法,靜態方法屬于類本身,而不是類的實例。抽象類中的靜態方法可以直接通過類名調用。但靜態方法不能被子類重寫。靜態方法屬于類本身,不屬于實例化的對象,因此它們的調用不受多態的影響。

12.2 示例:

abstract class Animal {static void info() {System.out.println("This is an animal");}
}class Dog extends Animal {// 不能重寫靜態方法// static void info() {}  // 錯誤,不能重寫靜態方法
}public class Main {public static void main(String[] args) {Animal.info();  // 調用Animal類的靜態方法}
}

盡管Animal是一個抽象類,但它仍然可以有靜態方法。靜態方法不能被子類重寫,它們可以通過類名直接訪問。

13. 抽象類的默認實現

13.1 解釋:

抽象類不僅可以聲明抽象方法,還可以提供默認實現。子類可以選擇繼承這個默認實現,也可以重寫這些方法。這種機制與接口的默認方法(default)類似。

13.2 示例:

// 定義一個抽象類Animal,包含一個默認實現的方法eat()和一個抽象方法sound()
abstract class Animal {// 默認實現:吃東西的方法void eat() {System.out.println("Animal is eating");}// 抽象方法:每個子類必須實現它來發出聲音abstract void sound();
}// Dog類繼承Animal類,只需要實現sound()方法
class Dog extends Animal {@Overridevoid sound() {System.out.println("Dog barks");}
}// Main類,用于執行和測試代碼
public class Main {public static void main(String[] args) {// 創建一個Dog對象Dog dog = new Dog();// 調用Dog類繼承的eat()方法(沒有被重寫,直接使用父類的默認實現)dog.eat();  // 輸出:Animal is eating// 調用Dog類自己實現的sound()方法dog.sound();  // 輸出:Dog barks}
}

在這個例子中,eat()方法在Animal類中有默認實現,Dog類繼承了eat()方法,但沒有重寫它。子類只需要實現sound()方法即可。

14. 抽象類中訪問父類的方法

14.1 子類通過super訪問父類中的成員方法和成員變量:

子類可以通過super關鍵字來訪問父類的成員方法和成員變量。對于抽象類中的方法,子類可以使用super來調用抽象類中已實現的非抽象方法。

示例:
abstract class Animal {void sound() {System.out.println("Animal makes a sound");}
}class Dog extends Animal {@Overridevoid sound() {super.sound();  // 調用父類的sound方法System.out.println("Dog barks");}
}public class Main {public static void main(String[] args) {Dog dog = new Dog();dog.sound();}
}
/*
輸出:
Animal makes a sound
Dog barks
*/

在上面的代碼中,Dog類通過super.sound()調用了Animal類中已實現的sound()方法。

14.2 子類通過super訪問父類中的構造方法:

在子類的構造方法中,super()可以用來調用父類的構造方法。如果父類沒有無參構造方法,子類的構造方法必須顯式調用父類的構造方法。

示例:
abstract class Animal {Animal(String name) {System.out.println("Animal constructor with name: " + name);}abstract void sound();
}class Dog extends Animal {Dog(String name) {super(name);  // 調用父類的構造方法System.out.println("Dog constructor");}@Overridevoid sound() {System.out.println("Dog barks");}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy");dog.sound();}
}

輸出:

Animal constructor with name:Buddy
Dog constructor
Dog barks

15. 抽象類與構造方法的調用

盡管抽象類不能被直接實例化,但它可以有構造方法。當子類創建對象時,會先調用父類的構造方法。子類的構造方法可以使用super()調用父類的構造方法。

示例:
abstract class Animal {Animal() {System.out.println("Animal constructor");}abstract void sound();
}class Dog extends Animal {Dog() {super();  // 調用父類構造方法System.out.println("Dog constructor");}@Overridevoid sound() {System.out.println("Dog barks");}
}public class abstract_Main2{public static void main(String args[]){Animal dog = new Dog();dog.sound();     }}

輸出:

Animal constructor
Dog constructor
Dog barks

16. 抽象類與final關鍵字的結合

  • final如果一個類被聲明為final,它不能被繼承。因此,抽象類不能是final類,因為抽象類必須被繼承才能實現。
  • final方法如果一個方法被聲明為final,它不能被重寫。雖然抽象類中的方法是抽象的,不能直接定義為final,但是如果子類實現了該方法,可以將其標記為final,防止進一步重寫。
示例:
// 定義一個抽象類Animal,包含一個final方法eat()和一個抽象方法sound()
abstract class Animal {// final方法,子類不能重寫final void eat() {System.out.println("Animal is eating");}// 抽象方法,子類必須實現abstract void sound();
}// Dog類繼承自Animal類,并實現sound()方法
class Dog extends Animal {@Overridevoid sound() {System.out.println("Dog barks");}// 不能重寫eat()方法,因為它是final方法// 如果你嘗試重寫eat()方法,編譯器會報錯// final void eat() {//     System.out.println("Dog is eating");// }
}// 主類,用于執行和測試代碼
public class Main {public static void main(String[] args) {// 創建一個Dog對象Dog dog = new Dog();// 調用Dog類繼承的eat()方法(它來自Animal類,不能被重寫)dog.eat();  // 輸出:Animal is eating// 調用Dog類自己實現的sound()方法dog.sound();  // 輸出:Dog barks}
}

在這個例子中,eat()方法在Animal類中被聲明為final,所以子類Dog不能重寫eat()方法。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/67721.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/67721.shtml
英文地址,請注明出處:http://en.pswp.cn/web/67721.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

css三角圖標

案例三角&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><s…

跨越通信障礙:深入了解ZeroMQ的魅力

在復雜的分布式系統開發中&#xff0c;進程間通信就像一座橋梁&#xff0c;連接著各個獨立運行的進程&#xff0c;讓它們能夠協同工作。然而&#xff0c;傳統的通信方式往往伴隨著復雜的設置、高昂的性能開銷以及有限的靈活性&#xff0c;成為了開發者們前進道路上的 “絆腳石”…

深入解析 COUNT(DISTINCT) OVER(ORDER BY):原理、問題與高效替代方案

目錄 一、累計去重需求場景 二、COUNT(DISTINCT) OVER(ORDER BY) 語法解析 2.1 基礎語法 2.2 執行原理 三、三大核心問題分析

線性數據結構:單向鏈表

放棄眼高手低&#xff0c;你真正投入學習&#xff0c;會因為找到一個新方法產生成就感&#xff0c;學習不僅是片面的記單詞、學高數......只要是提升自己的過程&#xff0c;探索到了未知&#xff0c;就是學習。 目錄 一.鏈表的理解 二.鏈表的分類&#xff08;重點理解&#xf…

基于PyQt5打造的實用工具——PDF文件加圖片水印,可調大小位置,可批量處理!

01 項目簡介 &#xff08;1&#xff09;項目背景 隨著PDF文件在信息交流中的廣泛應用&#xff0c;用戶對圖片水印的添加提出了更高要求&#xff0c;既要美觀&#xff0c;又需高效處理批量文件。現有工具難以實現精確調整和快速批量操作&#xff0c;操作繁瑣且效果不理想。本項…

MCU內部ADC模塊誤差如何校準

本文章是筆者整理的備忘筆記。希望在幫助自己溫習避免遺忘的同時&#xff0c;也能幫助其他需要參考的朋友。如有謬誤&#xff0c;歡迎大家進行指正。 一、ADC誤差校準引言 MCU 片內 ADC 模塊的誤差總包括了 5 個靜態參數 (靜態失調&#xff0c;增益誤差&#xff0c;微分非線性…

嵌入式硬件篇---CPUGPUTPU

文章目錄 第一部分&#xff1a;處理器CPU&#xff08;中央處理器&#xff09;1.通用性2.核心數3.緩存4.指令集5.功耗和發熱 GPU&#xff08;圖形處理器&#xff09;1.并行處理2.核心數量3.內存帶寬4.專門的應用 TPU&#xff08;張量處理單元&#xff09;1.為深度學習定制2.低精…

03-機器學習-數據獲取

一、流行機器學習數據集 主流機器學習數據集匯總 數據集名稱描述來源MNIST手寫數字圖像數據集&#xff0c;由美國人口普查局員工書寫。MNIST官網ImageNet包含數百萬張圖像&#xff0c;用于圖像分類和目標檢測。ImageNet官網AudioSet包含YouTube音頻片段&#xff0c;用于聲音分…

doris:STRUCT

STRUCT<field_name:field_type [COMMENT comment_string], ... > 表示由多個 Field 組成的結構體&#xff0c;也可被理解為多個列的集合。 不能作為 Key 使用&#xff0c;目前 STRUCT 僅支持在 Duplicate 模型的表中使用。一個 Struct 中的 Field 的名字和數量固定&…

一次端口監聽正常,tcpdump無法監聽到指定端口報文問題分析

tcpdump命令&#xff1a; sudo tcpdump -i ens2f0 port 6471 -XXnnvvv 下面是各個部分的詳細解釋&#xff1a; 1.tcpdump: 這是用于捕獲和分析網絡數據包的命令行工具。 2.-i ens2f0: 指定監聽的網絡接口。ens2f0 表示本地網卡&#xff09;&#xff0c;即計算機該指定網絡接口捕…

“新月智能武器系統”CIWS,開啟智能武器的新紀元

新月人物傳記&#xff1a;人物傳記之新月篇-CSDN博客 相關文章鏈接&#xff1a;星際戰爭模擬系統&#xff1a;新月的編程之道-CSDN博客 新月智能護甲系統CMIA--未來戰場的守護者-CSDN博客 “新月之智”智能戰術頭盔系統&#xff08;CITHS&#xff09;-CSDN博客 目錄 智能武…

實驗六 項目二 簡易信號發生器的設計與實現 (HEU)

聲明&#xff1a;代碼部分使用了AI工具 實驗六 綜合考核 Quartus 18.0 FPGA 5CSXFC6D6F31C6N 1. 實驗項目 要求利用硬件描述語言Verilog&#xff08;或VHDL&#xff09;、圖形描述方式、IP核&#xff0c;結合數字系統設計方法&#xff0c;在Quartus開發環境下&#xff…

SCRM系統如何提升客戶管理及業務協同的效率與價值

內容概要 在當今商業環境中&#xff0c;SCRM系統&#xff08;社交客戶關系管理系統&#xff09;正逐漸受到越來越多企業的關注和重視。隨著科技的發展&#xff0c;傳統的客戶管理方式已經無法滿足快速變化的市場需求&#xff0c;SCRM系統通過整合客戶數據和社交網絡信息&#…

[免費]微信小程序智能商城系統(uniapp+Springboot后端+vue管理端)【論文+源碼+SQL腳本】

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;看到一個不錯的微信小程序智能商城系統(uniappSpringboot后端vue管理端)&#xff0c;分享下哈。 項目視頻演示 【免費】微信小程序智能商城系統(uniappSpringboot后端vue管理端) Java畢業設計_嗶哩嗶哩_bilibili 項目介紹…

PID算法的數學實現和參數確定方法

目錄 概述 1 算法描述 1.1 PID算法模型 1.2 PID離散化的圖形描述 1.3 PID算法的特點 2 離散化的PID算法 2.1 位置式PID算法 2.2 增量式PID算法 2.3 位置式PID與增量式PID比較 3 控制器參數整定 3.1 PID參數確定方法 3.1.1 湊試法 3.1.2 臨界比例法 3.1.3 經驗法…

《DeepSeek R1:大模型最簡安裝秘籍》

DeepSeek R1&#xff1a;AI 大模型界的新起之秀 在人工智能的璀璨星空中&#xff0c;大模型如繁星般閃耀&#xff0c;而 DeepSeek R1 無疑是其中一顆冉冉升起的新星&#xff0c;自問世以來便吸引了全球的目光&#xff0c;在人工智能領域占據了重要的一席之地。 從性能表現上看…

【論文閱讀】RAG-Reward: Optimizing RAG with Reward Modeling and RLHF

研究背景 研究問題&#xff1a;這篇文章要解決的問題是如何優化檢索增強生成&#xff08;RAG&#xff09;系統&#xff0c;特別是通過獎勵建模和人類反饋強化學習&#xff08;RLHF&#xff09;來提高大型語言模型&#xff08;LLMs&#xff09;在RAG任務中的效果。研究難點&…

【數據結構】(3)包裝類和泛型

一、包裝類 1、什么是包裝類 將基礎類型包裝成的類就是包裝類。由于基礎類型不是繼承 Object 類的類&#xff0c;所以在泛型不能直接支持基礎類型&#xff0c;為了解決這個問題&#xff0c;就需要把基礎類型轉換為對應的包裝類。 基礎類型對應的包裝類 基礎類型包裝類byteByte…

DBUtils中QueryRunner(空參,傳數據源)構造方法的區別及應用場景

關于學習Spring框架時重構DAO層時&#xff0c;遇到的QueryRunner構造方法的問題&#xff0c;回憶MySQL中DBUtils部分 1. 空參構造方法 new QueryRunner() 特點&#xff1a; 不綁定數據源&#xff1a;QueryRunner 實例內部沒有 DataSource&#xff0c;因此無法自動獲取連接。 …

C++11線程

C11提供了線程庫&#xff0c;下面我們來看一下如何使用。 線程的創建 頭文件 要創建一個線程需要包一個線程頭文件:#include <thread> 我們先來看看thread支持的構造方式。 支持默認構造&#xff0c;直接使用thread創建一個空的線程對象。 也支持帶參的構造&#x…