java 抽象类 详解
目录
一、抽象类概述:
二、抽象方法 :
1.概述 :
2.应用 :
3.特点 :
三、抽象类特点 :
1.关于abstract关键字 :
2.抽象类不能被实例化,只能创建其子类对象 :
3.抽象类子类的两个选择 :
四、抽象类的成员 :
1.成员变量 :
2.成员方法 :
3.构造器 :
4.总结 :
5.代码演示 :
五、抽象类课堂练习 :
1.要求 :
2.思路 :
3.代码 :
六、总结 :
一、抽象类概述:
我们知道,类用来模拟现实事物。一个类可以模拟一类事物,而某个类的一个实例化对象可以模拟某个属于该类的具体的事物。类中描绘了该类所有对象共同的特性,当一个类中给出的信息足够全面时,我们就可以实例化该类;比方说,在Dog类中定义了name,age,fur_color,sex等属性,以及habit,eat等行为时,我们就可以创建一个Dog类对象,来模拟某个具体的Dog,比如你家的宠物狗,或者是神犬小七等。但是,当一个类中给出的信息不够全面时,(比方说有无法确定的行为),它给出的信息不足以描绘出一个具体的对象,这时我们往往不会实例化该类,这种类就是抽象类。打个比方,对于Animal类,是,所有的动物都有吃喝的行为,定义eat方法可以描述动物“吃”这一行为,但是每种动物吃的都不一样,因此一个eat方法并不能准确描述吃什么,怎么吃。这时Animal给出的信息就不足够描述一个对象,我们就不能去实例化Animal类。
在Java中,我们通过在类前添加关键字abstract(抽象的)来定义抽象类。如下图所示 :
public abstract class Animal {//Animal类此时就是一个抽象类。
}class Dog extends Animal {//Dog类继承了Animal类,是Animal类的子类。
}
二、抽象方法 :
1.概述 :
我们将“只有方法声明,没有方法体”的一类方法统称为抽象方法,抽象方法用关键字abstract修饰。需要注意的是,如果一个方法已经确定是抽象类,那么它绝不能再有方法体,即不能出现大括号,只需要在后面添加一个分号即可,否则IDEA会提示报错信息,如下图所示 :
还要注意一点,如果某个类中已经出现了抽象方法,那这个类必须定义成抽象类,否则会报错,如下GIF动图演示——我们删掉Animal类前的abstract修饰符,IDEA立马就会给出提示信息,如下 :
也就是说,拥有抽象方法的类一定是抽象类,但是抽象类不一定有抽象方法。
2.应用 :
当父类需要定义一个方法,却不能明确该方法的具体实现细节时,可以将方法定义为abstract,具体实现细节延迟到子类。(让子类重写这个方法)
就比如我们刚才说的,Animal类中的eat() 方法——我们可以将其先定义为抽象类,然后在子类,比如说Dog类中重写eat() 方法,给出对Dog对象“吃”这一行为的一些描述。如下 :
up以Animal类,Dog类和Test类为例,代码如下 :
package knowledge.polymorphism.about_abstract.introduction;public abstract class Animal { /** 父类 *///将Animal类中的eat() 方法定义为抽象类,具体实现延迟到子类。public abstract void eat();
}class Dog extends Animal { /** 子类 *///子类重写父类的抽象方法,也称为子类实现了该抽象方法。public void eat() {System.out.println("狗是杂食性动物,喜食肉类,喂养时应该以动物蛋白为主,素食为辅。");}
}class Test {public static void main(String[] args) {Dog dog = new Dog();dog.eat();}
}
运行结果 :
3.特点 :
①若父类中定义了一个抽象方法,要求其所有非抽象子类都必须重写该抽象方法。否则IDEA会报错,如下图所示 :
②前面我们说了,抽象方法用abstract关键字修饰。这里再补充一点——抽象方法不能再使用private,final 或者static关键字来修饰,即abstract不能与private,final和static共同出现,这是因为定义抽象方法的目的就是想将方法的具体实现延迟到子类,最终是要被子类重写的,而private,final,static这几个关键字都和“方法重写”的目的背道而驰。
如果你固执己见,非要让abstract和这几个关键字一同出现,IDEA也是毫不客气,直接报错,如下图所示 :
三、抽象类特点 :
1.关于abstract关键字 :
abstract关键字只能用于修饰类和方法,用于声明抽象类和抽象方法。抽象类必须使用abstract关键字修饰。声明时格式如下 :
访问权限修饰符 abstract class 类名{ // }
访问权限修饰符 abstract 返回值类型 方法名(形参列表);
举个例子,如下 :
//抽象类
public class Animal {//抽象方法public void eat(); //抽象方法最后加一个分号即可,不可以有大括号。
}
2.抽象类不能被实例化,只能创建其子类对象 :
即,我们不能创建抽象类对象(这里的对象指的是堆空间中真正的对象,即不能“new 抽象类”),原因我们在开篇抽象类的概述中也提到了,这里不再赘述。如果你头铁,非要创建抽象类对象,IDEA也不是吃素的,直接报错,如下图所示 :
当然,如果抽象类的子类没有用abstract关键字修饰,那么我们可以创建其子类对象,如下图所示 :
3.抽象类子类的两个选择 :
如果某个类继承了一个抽象类,那么这个类有两个选择——要么实现父类所有的抽象方法,要么子类本身也定义成抽象类。当然,肯定也不会是瞎jb想定义成抽象类就定义成抽象类😂,要满足我们我们上面所说的定义抽象类的条件——类中提供的信息不足以描述一个对象,或者类中有无法确定的行为需要延迟到子类实现。
还是给大家举个栗子。up现在在character包下创建一个Food类,将Food类定义为抽象类,并定义showNutrition()抽象方法,该方法将来要打印出食物的主要营养,具体实现延迟到子类;然后分别创建子类Meat类和Fruit类去继承Food类,我们在Meat类中重写Food类的showNutrition() 方法,使其打印出肉类的主要营养价值;同时,另一个子类Fruit类不去实现showNutrition() 方法,而是将其定义为抽象类。最后,以Test类为测试类,在测试类中创建子类对象并调用showNutrition() 方法。
Food类,Meat类,Fruit类,Test类代码如下 :
package knowledge.polymorphism.about_abstract.character;public abstract class Food { /** 父类 : Food类 *///记住,抽象方法没有方法体public abstract void showNutrition();
}class Meat extends Food { /** 子类 : Meat类 */@Overridepublic void showNutrition() {System.out.println("肉类是蛋白质、脂肪、维生素B2、维生素B1、烟酸和铁的重要来源。");}
}abstract class Fruit extends Food { /** 子类 : Fruit类 */
}class Test { /** 测试类 : Test类 */public static void main(String[] args) {Meat meat = new Meat();meat.showNutrition();}
}
运行结果 :
我们也可以再定义一个CiLi类表示水果中的刺梨,然后让刺梨类去继承Fruit类,并在CiLi类中去实现showNutrition() 方法;Fruit类不变,Test类和CiLi类代码如下 :
class CiLi extends Fruit {@Overridepublic void showNutrition() {System.out.println("刺梨是当之无愧的水果界的VC之王,VC含量高达2585mg/100g!");}
}class Test {public static void main(String[] args) {/** 测试类 : Test类 */Meat meat = new Meat();meat.showNutrition();System.out.println("----------------------------------------");CiLi ciLi = new CiLi();ciLi.showNutrition();}
}
运行结果 :
四、抽象类的成员 :
1.成员变量 :
抽象类既可以有静态的成员变量,也可以有非静态的成员变量。
既可以有静态的成员常量,也可以有非静态的成员常量。
2.成员方法 :
抽象类既可以有(非私有的)抽象方法(注意一定是非私有非静态,因为abstract关键字与private关键字,final关键字,static关键字不能同时存在);
也可以有非抽象方法(非抽象方法就可以用private,final和static关键字来修饰了,具体使用时,根据实际需求合理应用)。
3.构造器 :
抽象类可以和非抽象类一样拥有构造器,并且支持构造器的重载。
4.总结 :
其实吧,说上面一大堆都是废话😂。
抽象类中的成员只比非抽象类多一种——抽象方法。其他都和非抽象类一样。
大家只要记住抽象方法怎么写,怎么用就彳亍了。😎
5.代码演示 :
up以Fruit类为演示类,代码如下 :
package knowledge.polymorphism.about_abstract.about_members;public abstract class Fruit { //Fruit类是抽象类
//抽象类中可定义的成员://1.非静态变量和静态变量private String name = "水果名儿是有长有短";private static String size = "水果的大小是有大有小";//2.非静态常量和静态常量public final String COLOR = "水果的颜色是五光十色";public static final String FORM = "水果的形态是千奇百怪";//3.抽象方法和非抽象方法public abstract void nutrition();private final static void suitCrowds() {System.out.println("人人都适合吃水果!");}public void invokeSuitCrowds() {Fruit.suitCrowds();}//4.构造器可以重载public Fruit() {System.out.println("Fruit's name = " + name);}public Fruit(String name) {this.name = name;}
}
这些成员都可以在抽象类中定义,只要语法正确,IDEA是不会报错的,当然,具体怎么使用这些成员就看你自己了,根据实际情况来定。
五、抽象类课堂练习 :
1.要求 :
如上图所示 :
已知西风骑士团的三位骑士分别是琴,可莉和优菈,请分别定义类来描述它们,要求给出每一个西风骑士的姓名,年龄和性别;并且,这三人均可以使用元素之力,分别是元素战技和元素爆发,但每位骑士的战技和爆发都不一样。其中,琴使用风元素,元素战技为风压箭,元素爆发为蒲公英之风;可莉使用火元素,元素战技为蹦蹦炸弹,元素爆发为轰轰火花;优菈使用冰元素,元素战技为冰朝的涡旋,元素爆发为凝浪之光剑。请在这些类中正确选择一个类定义成抽象类,并在该类中定义抽象方法elemental_kill() 和 elemental_burst(),要求这两个抽象方法将来在实现时,需要在控制台打印出当前骑士的元素战技和元素爆发;并在该抽象类中定义非抽象方法,要求该方法可以在控制台打印出当前骑士的基本信息。
2.思路 :
①阅读提干后我们得知,总共有三个角色,这三个角色均属于名为“西风骑士团”的一个组织。因此,我们可以分别定义四个类来分别描述“西风骑士团”,“琴”,“可莉”,“优菈”,再加上测试类,因此我们总共需要定义五个类。
②“西风骑士团”可以代表一类人,由于每位骑士的元素战技和元素爆发均不相同,这个类并不能提供足够的信息来描述一个具体的“骑士”对象。所以,我们可以定义Knights类来表示“西风骑士团”,并将其定义为抽象类。又因为琴,可莉,优菈均属于西风骑士团的一员,因此我们可以分别定义Qin类,Keli类以及Youla类来描述这三位骑士,并让Qin类,Keli类和Youla类继承Knights类。
③题干要求定义两个抽象方法elemental_kill() 和 elemental_burst()来分别打印出当前骑士的元素战技和元素爆发。既然我们已经确定Knights类为抽象类,这就没啥好说了,在Knights类中定义这两个方法即可。
④又因为题干还要求我们在抽象类中定义方法打印出当前骑士的基本信息,因此,我们可以在Knights类定义name,age,sex这些属性;根据JavaBean标准,我们需要将这些属性全部设为私有,并给出公共的访问这些属性的方法,然后给出Knights类的无参构造和带参构造(注意,Knights是抽象类,无法被实例化,因此我们给出Knights构造器的目的不是为了创建Knights类对象,而是为了在子类的带参构造中使用super语句调用父类构造器;接着,再定义一个printInfo方法,用于打印出当前骑士的姓名,年龄和性别。
⑤最后,我们可以定义测试类Test类,并分别创建Qin类,Keli类和Youla类对象,调用elemental_kill()方法,elemental_burst() 方法,以及printInfo方法。
3.代码 :
package knowledge.polymorphism.about_abstract.exercise;public abstract class Knights { /** 骑士类 */private String name;private int age;private String sex;public Knights() {}public Knights(String name, int age, String sex) {this.name = name;this.age = age;this.sex = sex;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public abstract void elemental_skill();public abstract void elemental_burst();public void printInfo() {System.out.println("西风骑士——" + getName() + "," + getAge() + "岁,性别" + getSex());}
}class Qin extends Knights{ /** 琴类 */public Qin(String name, int age, String sex) {super(name, age, sex);}@Overridepublic void elemental_skill() {System.out.println("琴的元素战技是风压箭。");}@Overridepublic void elemental_burst() {System.out.println("琴的元素战技是蒲公英之风。");}
}
class Keli extends Knights{ /** 可莉类 */public Keli(String name, int age, String sex) {super(name, age, sex);}@Overridepublic void elemental_skill() {System.out.println("可莉的元素战技是蹦蹦炸弹。");}@Overridepublic void elemental_burst() {System.out.println("可莉的元素战技是轰轰火花。");}
}
class Youla extends Knights{ /** 优菈类 */public Youla(String name, int age, String sex) {super(name, age, sex);}@Overridepublic void elemental_skill() {System.out.println("优菈的元素战技是冰朝的涡旋。");}@Overridepublic void elemental_burst() {System.out.println("优菈的元素战技是凝浪之光剑。");}
}class Test { /** 测试类 */public static void main(String[] args) {Qin qin = new Qin("琴", 22, "female");qin.elemental_skill();qin.elemental_burst();qin.printInfo();System.out.println("-------------------------------------------");Keli keli = new Keli("可莉", 500, "female");keli.elemental_skill();keli.elemental_burst();keli.printInfo();System.out.println("-------------------------------------------");Youla youla = new Youla("优菈", 21, "female");youla.elemental_skill();youla.elemental_burst();youla.printInfo();}
}
六、总结 :
🆗,以上就是本节抽象类相关的全部内容了,大家一定要牢记抽象类和抽象方法的特点,牢记抽象类和抽象方法之间的关系,掌握abstract关键字的使用。下一节内容是多态章的final关键字,我们不见不散😆。感谢阅读!
相关文章:

java 抽象类 详解
目录 一、抽象类概述: 二、抽象方法 : 1.概述 : 2.应用 : 3.特点 : 三、抽象类特点 : 1.关于abstract关键字 : 2.抽象类不能被实例化,只能创建其子类对象 : 3.抽象类子类的两个选择 : 四、抽象类的成员 : 1.成员变量 : 2.成员方…...

MySQL的安装(详解)
文章目录前言一、yum方式安装1、下载并安装MySQL2、 启动MySQL数据库3、查看MySQL初始密码4、登录数据库5、修改MySQL默认密码6、授予root用户远程管理权限7、输入exit退出数据库二、rpm安装方式1、检查2、卸载mariadb3、安装4、启动5、密码总结前言 本教程为Linux下安装mysql的…...

界面控件DevExpress WinForm——轻松构建类Visual Studio UI(二)
DevExpress WinForm拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任…...

BabylonJS之放烟花
一: 技术调研 1. 方案一:ParticleSystem 用ParticleSystem来实现每一束的烟花效果,如果浏览器支持WebGL2功能,使用GPUParticleSystem性能会有极大的提升。 优点: 烟花效果易实现且效果好。 缺点: 每一个P…...

vue3 布局样式的原理
style scoped <style scoped > 它的 CSS 只作用于当前组件中的元素,如果子组件只有一个根元素,也会被渗透 原理: 当我们再组建中使用scoped时,vue会自动为组件中所有元素生成一个随机的属性,形如:da…...

Qt程序使用路径方式和注意事项
Qt程序使用路径方式和注意事项 更多精彩内容👉个人内容分类汇总 👈👉Qt开发经验 👈文章目录Qt程序使用路径方式和注意事项[toc]前言一、Windows下Qt程序使用路径1.准备工作2.测试结果二、Linux下Qt程序使用路径1.准备工作2.测试结…...

和日期相关的代码和bug——一道力扣题中的小发现
目录 Day of the Week 题目大意 常规方法 Python代码 Golang代码 C代码 基姆拉尔森公式 Python代码 Golang代码 C代码 使用库函数 Python代码 Golang代码 C代码 Day of the Week Given a date, return the corresponding day of the week for that date. The inp…...
如何在2023年学习编程并获得开发者工作
丢下自负 许多进入软件开发领域的人都是从最底层开始的,你可能会获得“初级开发者”的头衔。每天面临的问题是:我有十年的专业经验了。我不是个入门员工。但尽管过去的工作经验丰富,我仍然是个入门级的开发者,我还是个新手。别总…...

Python实战之小说下载神器(三)排行榜所有小说:最全热门小说合集,总有一款适合你,好多好多好多超赞的小说...(源码分享学习)
前言 这次的是一个系列内容 给大家讲解一下何一步一步实现一个完整的实战项目案例系列之 小说下载神器(三)(GUI界面化程序) 多线程采集小说下载、采集排行榜所有小说 哈喽!大家上午好啦,我是爱看小说的栗子…...
前端监控之用户行为监控实践1(数据收集)
前文对前端监控进行了简单介绍,起因是因为当前做的一个需求,老板要看当前项目的uv、pv信息。其实这是非常简单的统计。 但在最开始接到这个需求,却难倒我了。 现在进行简单的复盘,记录一下实现方法。 一、数据记录 用户行为从大…...

【网络原理7】认识HTTP
目录 一、HTTP协议的位置 二、HTTP协议的特点&应用场景 三、HTTP协议的格式的查看 Fiddler下载与使用 编辑 如何查看HTTP请求消息 编辑 如何查看HTTP响应数据包 如何默认开启HTTPS的解析功能 四、HTTP的请求数据包的格式含义 第一部分:请求行&…...

SPI实验
目录 一、SPI 简介 二、硬件原理 ECSPI3_SCLK ECSPI3_MISO和ECSPI3_MOSI ECSPI3_SS0 三、I.MX6U ECSPI 简介 ECSPIx_RXDATA ECSPIx_TXDATA ECSPIx_CONREG ECSPIx_CONFIGREG ECSPIx_PERIODREG编辑 ECSPIx_STATREG 四、ICM-20608 简介 五、代码编写 1、创建文件及文…...

去基线处理
目录detrend函数去除基线多项式拟合原函数BEADS 基线处理小波算法经验模态分解(EMD)参考detrend函数去除基线 detrend函数只能用于去除线性趋势,对于非线性的无能为力。 函数表达式:y scipy.signal.detrend(x): 从信号中删除线…...

模拟信号4-20mA /0-5V/0-75mV/0-100mV转RS-485/232,数据采集A/D转换模块 YL21
特点:● 模拟信号采集,隔离转换 RS-485/232输出● 采用12位AD转换器,测量精度优于0.1%● 通过RS-485/232接口可以程控校准模块精度● 信号输入 / 输出之间隔离耐压3000VDC ● 宽电源供电范围:8 ~ 32VDC● 可靠性高,编程…...
[USB]键盘数据格式以及按键键值
USB键盘数据包含8个字节 BYTE1 – 特殊按键 |–bit0: Left Control是否按下,按下为1 |–bit1: Left Shift 是否按下,按下为1 |–bit2: Left Alt 是否按下,按下为1 |–bit3: Left GUI(Windows键) 是否按下,…...

web客户端-websocket
1、websocket简介 WebSocket是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,…...

mysql间隙锁
首先我们这里有一个表t,其中的数据如下图所示 注意哈 update由于操作的最新的值,所以是当前读! 另外一个事务插入 8的时候发生锁 而我对id为10的数据进行更新,却不会被锁住 分析:在执行当前读时,由于id7不存…...
华为OD机试 - 计算面积(Java) | 机试题+算法思路+考点+代码解析 【2023】
计算面积 绘图机器的绘图笔初始位i在原点(0.0)。 机器启动后其绘图笔按下面规则绘制直线: 1 )尝试沿着横向坐标轴正向绘制直线,直到给定的终点值E, 2 )期间可通过指令在纵坐标轴方向进行偏移。井同时绘制直线,偏移后按规则1绘制直线;指令的格式为X offsetY。表示在横坐标X…...
Python 之 Pandas 时间戳、通过时间间隔实现 datetime 加减、时间转化、时期频率转换和 shift() 时间频率进行移位)
文章目录一、时间戳1. unit 参数是 s2. year、month、day、hour、minute、second、microsecond 单独设置时间二、通过时间间隔实现 datetime 加减三、时间转化1. 处理各种输入格式2. 将字符串转 datetime3. 除了可以将文本数据转为时间戳外,还可以将 unix 时间转为时…...

一篇文章搞定linux网络模型
网络协议感觉晦涩难懂?什么七层网络模型?又五层网络模型?又四层网络模型?TCP/IP协议是个啥?UDP是啥?什么是三次握手?什么是四次挥手?tcpdump听说是抓包的,怎么用…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...