java 抽象类 详解

news2024/12/26 11:40:24

目录

一、抽象类概述:

二、抽象方法 : 

        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类 */
    @Override
    public 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 {
    @Override
    public 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);
    }

    @Override
    public void elemental_skill() {
        System.out.println("琴的元素战技是风压箭。");
    }

    @Override
    public void elemental_burst() {
        System.out.println("琴的元素战技是蒲公英之风。");
    }
}
class Keli extends Knights{                 /** 可莉类 */
    public Keli(String name, int age, String sex) {
        super(name, age, sex);
    }

    @Override
    public void elemental_skill() {
        System.out.println("可莉的元素战技是蹦蹦炸弹。");
    }

    @Override
    public void elemental_burst() {
        System.out.println("可莉的元素战技是轰轰火花。");
    }
}
class Youla extends Knights{                /** 优菈类 */
    public Youla(String name, int age, String sex) {
        super(name, age, sex);
    }

    @Override
    public void elemental_skill() {
        System.out.println("优菈的元素战技是冰朝的涡旋。");
    }

    @Override
    public 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关键字,我们不见不散😆。感谢阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/366764.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

趣味三角——第12章——tanx

第12章节 tanx In his very numerous memoires, and especially in his great work, Introductio in analysin infinitorum (1748), Euler displayed the most wonderful skill in obtaining a rich harvest of results of great interest. . . . Hardly any other work …

业务单据堆积如山?如何提升会计做账效率?

某集团以“创建现代能源体系、提高人民生活品质”为使命,形成了贯通下游分销、中游贸易储运、上游生产的清洁能源产业链和涵盖健康、文化、旅游、置业的生命健康产品链。目前,某集团在全国21个省,为超过2681万个家庭用户、21万家企业提供能源…

Android:同步屏障的简单理解和使用

同步屏障的简单理解和使用1、背景2、何为同步屏障?2.1、 发送屏障消息——postSyncBarrier2.2、发送异步消息2.3、处理消息2.4、移除屏障消息——removeSyncBarrier2、系统什么时候添加同步屏障?参考1、背景 这里我们假设一个场景:我们向主线…

网狐服务端C++引入http功能剖析

旗舰版本的网狐服务端及以前的版本都是没有http解析功能的,导致就是web后台改了配置不能及时通知到游戏里面去,以至于很多小公司拿这种框架来开发的变通的方案就是用定时器不定时去刷数据库,导致多少个功能就有多少个定时去刷新,代…

0基础学习软件测试难么

0基础开始学习任何一样事情都是有一定难度的,但是也要有对比,软件测试相比于IT行业其他学科已经算是容易入门的了,就看你个人的学习方法,找的学习资源以及你的自制力。 正确学习方法路径 “我一听就懂,一敲就废&…

【Spring的事务传播行为有哪些呢?Spring事务的隔离级别?讲下嵌套事务?】

如果你想寻求一份与后端相关的开发工作,那么关于Spring事务相关的面试题你就不能说不会并且不能不知道? 人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步? 一.Spring中声明事务的方式 1.1 编程式事务 编程…

Android Gradle脚本打包

1、背景资料 1.1 Android-Gradle-Groovy-Java-JVM 之间的关系 1.2 Android Gradle Plugin Version版本 与 Gradle Version版本的对应关系 Android Gradle Plugin Version版本Gradle Version版本1.0.0 - 1.1.32.2.1 - 2.31.2.0 - 1.3.12.2.1 - 2.91.5.02.2.1 - 2.132.0.0 -…

WFP网络过滤驱动-限制网站访问

文章目录前言WFP入门介绍WFP基本架构名词解释代码基本结构代码示例前言 WFP Architecture - Win32 apps | Microsoft Learn是一个网络流量处理平台。WFP 由一组连接到网络堆栈的钩子和一个协调网络堆栈交互的过滤引擎组成。 本文使用WFP,实现了一个网络阻断的demo…

Guna UI WinForms 2.0.4.4 Crack

Guna.UI2 WinForms is the suite for creating groundbreaking desktop app UI. It is for developers targeting the .NET Windows Forms platform. 50 多个 UI 控件 具有广泛功能的综合组件可帮助您开发任何东西。 无尽的定制 只需拖放即可创建视觉效果命令和体验。 出色的…

服务端开发之Java备战秋招面试篇2-HashMap底层原理篇

现在Java应届生和实习生就业基本上必问HashMap的底层原理和扩容机制等,可以说是十分常见的面试题了,今天我们来好好整理一下这些知识,为后面的秋招做足准备,加油吧,少年。 目录 1、HashMap集合介绍 2、HashMap的存储…

S2-001漏洞分析

首发于个人博客:https://bthoughts.top/posts/S2-001漏洞分析/ 一、简介 1.1 Struts2 Struts2是流行和成熟的基于MVC设计模式的Web应用程序框架。 Struts2不只是Struts1下一个版本,它是一个完全重写的Struts架构。 1.2 S2-001 Remote code exploit o…

【保姆级】手把手捋动态代理流程(JDK+Cglib超详细源码分析)

简介动态代理,通俗点说就是:无需声明式的创建java代理类,而是在运行过程中生成"虚拟"的代理类,被ClassLoader加载。 从而避免了静态代理那样需要声明大量的代理类。上面的简介中提到了两个关键的名词:“静态…

C语言进阶(九)—— 函数指针和回调函数、预处理、动态库和静态库的使用、递归函数

1. 函数指针1.1 函数类型通过什么来区分两个不同的函数?一个函数在编译时被分配一个入口地址,这个地址就称为函数的指针,函数名代表函数的入口地址。函数三要素: 名称、参数、返回值。C语言中的函数有自己特定的类型。c语言中通过…

多元回归分析 | ELM极限学习机多输入单输出预测(Matlab完整程序)

多元回归分析 | ELM极限学习机多输入单输出预测(Matlab完整程序) 目录 多元回归分析 | ELM极限学习机多输入单输出预测(Matlab完整程序)预测结果评价指标基本介绍程序设计参考资料预测结果 评价指标 -----------ELM结果分析-------------- 均方根误差(RMSE):0.55438 测试集…

webgis高德地图

webgis高德地图 首先准备工作,注册一个高德地图账号,然后在创建一个新应用生一个key跟appId 高德开放平台 接着创建一个html页面 高德配置手册 <style>* {margin: 0;padding: 0;}#

如何维护固态继电器?

固态继电器是SSR的简称&#xff0c;是由微电子电路、分立电子器件和电力电子功率器件组成的非接触式开关。隔离装置用于实现控制端子与负载终端之间的隔离。固态继电器的输入端使用微小的控制信号直接驱动大电流负载。那么&#xff0c;如何保养固态继电器呢&#xff1f; 在为小…

Editor工具开发基础一:顶部菜单栏拓展

一.创建脚本路径 不管是那种工具 都需要在工程里创建一个Editor文件夹 来存放工具.cs文件 二.特性 MenuItem 特性 修饰静态方法 三个构造函数 public MenuItem(string itemName); public MenuItem(string itemName, bool isValidateFunction); public MenuItem(string itemN…

手工测试用例就是自动化测试脚本——使用ruby 1.9新特性进行自动化脚本的编写

昨天因为要装watir-webdriver的原因将用了快一年的ruby1.8.6升级到了1.9。由于1.9是原生支持unicode编码&#xff0c;所以我们可以使用中文进行自动化脚本的编写工作。 做了简单的封装后&#xff0c;我们可以实现如下的自动化测试代码。请注意&#xff0c;这些代码是可以正确运…

【2023考研数学二考试大纲】

文章目录I 考试科目II考试形式和试卷结构一、试卷满分及考试时间二、答题方式三、试卷内容结构四、试卷题型结构III考查内容【高等数学】一、函数、极限、连续二、一元函数微分学三、一元函数积分学四、多元函数微积分学五、常微分方程【线性代数】一、行列式二、矩阵三、向量四…

新手入门吉他推荐,第一把吉他从这十款选绝不踩雷!初学者吉他选购指南【新手必看】

一、新手购琴注意事项&#xff1a; 1、预算范围 一把合适的吉他对于初学者来说会拥有一个很好的音乐启蒙。选一款性价比高&#xff0c;做工材料、音质和手感相对较好的吉他自然不会是一件吃亏的事。**初学者第一把琴的预算&#xff0c;我觉得最低标准也是要在500元起&#xf…