[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.mzph.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…

线性数据结构:单向链表

放弃眼高手低&#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;微分非线性…

“新月智能武器系统”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 经验法…

【论文阅读】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…

C++11线程

C11提供了线程库&#xff0c;下面我们来看一下如何使用。 线程的创建 头文件 要创建一个线程需要包一个线程头文件:#include <thread> 我们先来看看thread支持的构造方式。 支持默认构造&#xff0c;直接使用thread创建一个空的线程对象。 也支持带参的构造&#x…

Golang 并发机制-3:通道(channels)机制详解

并发编程是一种创建性能优化且响应迅速的软件的强大方法。Golang&#xff08;也称为 Go&#xff09;通过通道&#xff08;channels&#xff09;这一特性&#xff0c;能够可靠且优雅地实现并发通信。本文将揭示通道的概念&#xff0c;解释其在并发编程中的作用&#xff0c;并提供…

笔记:使用ST-LINK烧录STM32程序怎么样最方便?

一般板子在插件上&#xff0c; 8脚 3.3V;9脚 CLK;10脚 DIO;4脚GND ST_Link 19脚 3.3V;9脚 CLK;7脚 DIO;20脚 GND 烧录软件&#xff1a;ST-LINK Utility&#xff0c;Keil_5; ST_Link 接口针脚定义&#xff1a; 按定义连接ST_Link与电路板&#xff1b; 打开STM32 ST-LINK Uti…

网络测试工具

工具介绍&#xff1a; 这是一个功能完整的网络测速工具&#xff0c;可以测试网络的下载速度、上传速度和延迟。 功能特点&#xff1a; 1. 速度测试 - 下载速度测试 - 上传速度测试 - Ping延迟测试 - 自动选择最佳服务器 2. 实时显示 - 进度条显示测试进度 - 实时显示测试状…

java每日精进1.31(SpringSecurity)

在所有的开发的系统中&#xff0c;都必须做认证(authentication)和授权(authorization)&#xff0c;以保证系统的安全性。 一、基础使用 1.依赖 <dependencies><!-- 实现对 Spring MVC 的自动化配置 --><dependency><groupId>org.springframework.bo…

17.2 图形绘制8

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 17.2.10 重绘 先看以下例子&#xff1a; 【例 17.28】【项目&#xff1a;code17-028】绘制填充矩形。 private void button1_Clic…

自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数

import numpy as np import torch import torch.nn as nn import torch.optim as optim from sklearn.metrics import precision_score, recall_score, f1_score# 数据准备 class1_points np.array([[1.9, 1.2],[1.5, 2.1],[1.9, 0.5],[1.5, 0.9],[0.9, 1.2],[1.1, 1.7],[1.4,…

neo4j入门

文章目录 neo4j版本说明部署安装Mac部署docker部署 neo4j web工具使用数据结构图数据库VS关系数据库 neo4j neo4j官网Neo4j是用ava实现的开源NoSQL图数据库。Neo4作为图数据库中的代表产品&#xff0c;已经在众多的行业项目中进行了应用&#xff0c;如&#xff1a;网络管理&am…

Java基础——分层解耦——IOC和DI入门

目录 三层架构 Controller Service Dao ​编辑 调用过程 面向接口编程 分层解耦 耦合 内聚 软件设计原则 控制反转 依赖注入 Bean对象 如何将类产生的对象交给IOC容器管理&#xff1f; 容器怎样才能提供依赖的bean对象呢&#xff1f; 三层架构 Controller 控制…