Java基础语法之抽象类和接口

抽象类

什么是抽象类

并不是所有的类都是用来描述对象的,这样的类就是抽象类

例如,矩形,三角形都是图形,但图形类无法去描述具体图形,所以它的draw方法无法具体实现,这个方法就可以没设计成抽象方法,这个类就是抽象类

抽象类语法

被abstract修饰的类是抽象类,abstract修饰的方法是抽象方法,抽象方法不用给出具体的实现体 

如上,draw方法没有具体实现体,也就是不用写代码块

继承了抽象类的子类必须重写所有的抽象方法。如下:

如何使用该抽象类及其子类

这就是一种使用方法,在main函数中调用了Test中的静态方法draw(注意一定要是静态的,在静态方法中不可以调用非静态方法,因为非静态方法的调用依赖对象,而静态方法不依赖对象,所以静态方法默认没有this参数,也就无法调用非静态方法)

draw方法的参数是Shape类,而我们传参时传的是其子类,这里就发生了向上转型;

在draw方法中调用shape.draw()时,又会发生动态绑定;

总之这也是多态。

抽象类的特性

1.不能实例化本抽象类的对象

但是可以用它实例化一个子类对象,也就是可以发生向上转型

因为向上转型后,对象的本质还是其子类,只不过用父类来接收了,并不代表实例化了一个父类对象。

2.抽象方法不可以是private权限,也不可以被final,static修饰

首先,子类重写方法的访问权限要大于等于父类;

其次,final修饰的方法是静态方法,static修饰的方法在方法区;

总之,被private,final,static修饰的方法不可以被重写

3.继承抽象类的子类必须重写其方法,否则子类也要被abstract修饰,然后它的继承者要将其父类以及父类的父类中所有的抽象方法重写

4.抽象类中不一定有抽象方法,但由抽象方法的一定是抽象类

5.抽象类中也可以有普通方法和成员

但它里面的普通成员变量及方法只能通过子类对象来调用

其中,shape引用是发生了向上转型的,而reck就是一个子类的引用,由于有继承关系,所以可以通过子类引用来调用抽象类的方法

6.抽象类中可以有构造方法,供子类创建对象时初始化父类的成员变量,但注意,构造方法不能是抽象方法,因为构造方法不可以被重写

抽象类的作用

很多工作不应由父类完成,而应由子类来完成,但如果是一个普通类,用父类的引用去调用某些方法时就不会报错,而要是抽象类就会报错

就比如画图,你要是用父类shape来调用draw方法,如果不是抽象类就能正常编译,但由于图形有很多种,所以shape这个引用画不出具体的图形;而要是抽象类就会及时报错,提醒你调用具体的子类来画图

接口

什么是接口

接口就是公共的行为标准,大家在实现时,只要符号规范标准就可以通用。

具体点说,接口就是多个类的公共规范,是一种引用数据类型。

语法规则

接口要用interface关键字定义,内部是抽象方法;例如:

接口的使用

有了接口就必须要有具体的类来使用这就要用到implements关键字

public class 类名 implements 接口名{

}

如果这个类还和其他类由继承关系,则应该:

public class 类名 extends 父类名 implements 接口名{

}   表示该子类继承了某个类并且还有某个功能

既然都有继承关系了,为什么还要有接口呢?一个父类可以引出多个子类,它们都是由共性的,但也有特性,这些特性就不适合写在父类里面,这时就可以提供接口,有什么功能就使用什么接口

举例:

接口的特性

1.接口默认是被abstract修饰的,因为它里面有抽象方法

 interface USB等价于abstract interface USB

2.接口中的方法默认是被public abstract修饰的(也只能是这种权限,其他的都会报错)

void func();  等价于public abstract void func();

这也好理解,接口是一种公共标准,一定得是公开的抽象的

3.接口是一种引用类型,但不能直接new一个接口对象

4.接口中可以有成员变量,但这些变量默认是public static final修饰的。既然默认被final修饰了,那么在定义的时候就必须初始化

首先  int a=10;等价于public static final int a=10;

其次,不可以直接int a;必须初始化

5.接口中一般不可以有普通方法,但被static default修饰的方法除外

但注意:static void func(){}等价于public static void func(){},不可以改成除public的其他权限,default也一样

对于被static修饰的方法,可以直接用接口名调用,而default修饰的方法只能用子类对象调用或者被重写

例如:

package Demo2;
interface A{
    void Testa();
    static void Testb(){
        System.out.println("A 的static方法");
    }
    default void Testc(){
        System.out.println("A的default方法");
    }
}
class B implements A{
    @Override
    public void Testa() {
        System.out.println("B重写的testa方法");
    }

    @Override
    public void Testc() {
        A.super.Testc();
    }
}

public class Test {
    public static void main(String[] args) {
        A.Testb();
        B b=new B();
        b.Testa();
        b.Testc();
    }
}

用static修饰的方法可以在main中直接用接口名调用,但default方法要么被重写,要么用子类实例化的对象来调用

6.重写接口中的抽象方法时,只可以设置为public权限,因为接口中的抽象方法默认是public的,所以子类的方法权限要大于等于public

7.接口中不能有静态代码块和构造方法

8.如果它的子类没有重写抽象方法,那这个类必须设置为抽象类

举例

abstract interface USB{
    void openDevice() ;

    void closeDevice();
}
class Mouse implements USB{
    @Override
    public void openDevice() {
        System.out.println("打开鼠标");
    }
    public void click(){
        System.out.println("疯狂点击鼠标");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭鼠标");
    }
}
class KeyBoard implements USB{
    @Override
    public void openDevice() {
        System.out.println("打开键盘");
    }
    public void input(){
        System.out.println("疯狂打字");
    }
    @Override
    public void closeDevice() {
        System.out.println("关闭键盘");
    }
}
class Computer {
    public void powerOn() {
        System.out.println("打开电脑");
    }
    public void powerOff() {
        System.out.println("关闭电脑");
    }
    public void useDevice(USB usb){
        usb.openDevice();

        if(usb instanceof Mouse){
            Mouse mouse=(Mouse) usb;
            mouse.click();
        }
        else if(usb instanceof KeyBoard){
            KeyBoard keyBoard=(KeyBoard) usb;
            keyBoard.input();
        }
        usb.closeDevice();

    }
}
public class Test {
    public static void main(String[] args) {
        Computer computer=new Computer();
        computer.powerOn();
        KeyBoard keyBoard=new KeyBoard();
        Mouse mouse=new Mouse();
        computer.useDevice(keyBoard);
        computer.useDevice(mouse);
        computer.powerOff();
    }
}

如上,电脑有usb接口,可以实现打开关闭键盘鼠标的操作

注意,电脑本身不需要usb接口来打开,所以电脑是一个独立的类,它通过自己的powerOn powerOff 方法来打开,然后它又有使用设备的方法,然后就是设备要通过usb接口来打开关闭,即usb.openDevice(); usb.closeDevice();但是在打开后,还要工作,可是只用USB类无法调用设备独有的功能,所以发生了向下转型,注意instanceof的判断和括号的类型强转

然后在main函数中,首先实例化一个电脑对象,将电脑打开,再实例化键盘和鼠标,然后就是电脑要开始使用设备了,调用useDevice函数(这里发生了向上转型,因为是用USB这个引用去接收各种需要USB的对象)。最后就关闭电脑

实现多个接口

在Java中,类和类之间只能单继承,一个类只能有一个父类,但是一个类可以有多个特殊的功能,即一个类可以有多个接口

class 类名 implements 接口1,接口2

例如:青蛙会跑也会游泳,鸭子会跑会游泳也会飞,如下

class Animal{
    String name;
    int age;
    public void eat(){
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
 interface Running{
    public abstract void run() ;
}
interface Swimming{
    public abstract void swim();
}
interface Flying{
    public abstract void fly();
}
class Dog extends Animal implements Running{
    public Dog(String name, int age) {
        super(name, age);
    }
    @Override
    public void run() {
        System.out.println("正在用囧囧跑步步");
    }

    @Override
    public void eat() {
        System.out.println("吃狗粮");
    }
}
class Flog extends Animal implements Running,Swimming{
    @Override
    public void run() {
        System.out.println("正在用俩只大脚掌跑步步");
    }
    @Override
    public void swim() {
        System.out.println("正在用那小手手游泳");
    }
    public Flog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("吃蛙粮");
    }
}
class Duck extends Animal implements Running,Flying,Swimming{
    @Override
    public void run() {
        System.out.println("正在小跑");
    }
    @Override
    public void swim(){
        System.out.println("正在划水");
    }
    @Override
    public void fly() {
        System.out.println("正在扇翅膀飞飞");
    }
    public Duck(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("正在吃鸭粮");
    }
}

这就是一个典型的例子

那如何使用呢?

在main函数中可以调用这些static修饰的方法。在=========的上方,是多态的典型例子,将子类对象给到父类,再发生动态绑定,调用重写的方法,

在============的下方就是在使用接口了。注意public static void run(Running run),这个方法的参数是Running这个引用类型,当有此功能的对象给到这个引用类型时,就是发生了向上转型,所以在run.run()时,表面上是调用了接口的抽象方法,实际上是在调用子类的重写的方法

其实,只要是有这个功能的类,就可以实现这个接口

接口间的继承

在Java中,类和类之间是单继承的,但接口与接口可以多继承

package Demo4;
interface A {
    void testA();
}

interface B {
    void testB();
}
interface C extends A,B{
    void testC();
    void testA();
}
class TestDemo1 implements C {
    @Override
    public void testC() {

    }

    @Override
    public void testA() {

    }

    @Override
    public void testB() {

    }
}

public class Test {
}

接口举例

comparable

想要比较俩个学生的大小

单纯这样是不行的,我们要指定如何比较,拿什么比较,这就要用到comparable接口

这是一个接口,尖括号里面的T是要比较的数据的类型,如果要比较student,就在里面写student。这个接口里面有一个抽象方法,所以我们要重写这个抽象方法;以用年龄比较为例

注意,尖括号不能省略

但是,如果需求改变,又想用姓名比较,我们就又得把重写的方法改了,而不可以再写一个重写方法(抽象方法只可以被重写一份)很麻烦

所以就有了下面的比较器

comparator

它里面有很多抽象方法,但我们只用到了比较,所以重写比较即可

先看例子

这是年龄比较器,那要是名字比较器呢?不能直接返回o1.name-o2.name,因为name是String类型,不可以相加减。这时就需要用到String下面的compareTo方法

使用的时候就要实例化比较器这个对象

com

上面这个是String类下面的compareTo方法,其实是String类使用了comparable接口,所以重写了comepareTo方法

总结

comparable对类的侵入性比较强,是要比较哪个类,就要让哪个类implements它,是在类里面重写方法。一旦写死了,就只可以用这一种比较方法

comparator更加灵活,只要传入要比较的对象即可,只不过注意要实例化比较器对象因为comparator这是一个接口,里面的抽象方法无法调用,只有放到类里面才能发挥作用,需要我们按自己的意愿重写

再例如

我们可以这样对整型数组排序,那能否对学生数组排序呢?

显然是不可以的,来看一下源码

这里用到了Comparable接口,即将俩个对象强转为了comparable类型,所以要想成功排序,Student类就要使用这个接口,并且重写这个comepareTo方法

然后就可以正常排序了,但最好再自己重写一个toString方法,要不然就会出现上面的打印情况(上面这个最终是调用的object类的toString方法,而object类是所有子类的父类,所以当我们再Student类中重写了方法后就会调用我们自己的方法),如下

其实,sort有很多重载方法,比如下面这个:

它是有俩个参数,其中一个是要排序的数组,另一个就是Comparator这个接口(但不是说要传这个接口,而是要传实现这个接口的类型的引用)

那么我们就可以如下这种方式来排序

总结:

既然对于整型数组可以直接用arrays.sort排序,那就说明一个事实,Integer这个类一定implements了comparable这个接口,我们可以看一下源码:

自己写一个排序方法

因为排序不仅仅是为一个类提供,而是为多个类提供,所以参数要设置成Comparable类的数组,这样的话,只要是实现了这个接口的类,都可以用到这个排序方法。注意,里面的交换语句其实交换的是引用的指向(相当于C语言中指针的指向)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【漏洞复现】Node.js 目录穿越漏洞(CVE-2017-14849)

文章目录 1.1、漏洞描述1.2、影响版本1.3、漏洞复现1、基础环境2、漏洞验证3、漏洞分析 1.4、参考 1.1、漏洞描述 原因是 Node.js 8.5.0 对目录进行normalize操作时出现了逻辑错误,导致向上层跳跃的时候(如../../../../../../etc/passwd)&am…

闲人闲谈PS之四十九——PLM和SAP集成常见的问题

惯例闲话:天气突变,没想到珠三角也骤降了10几度,昨晚还吹风扇模式,早上起来一下子感觉丝丝凉意。闲人还是喜欢冬天,冷,能让人思维清晰,提高工作效率。趁着天气适宜,赶紧加班擦屁股去…

关于pycharm无法进入base界面的问题

问题:terminal输入activate无法进入base 解决方案 1.Cortana这边找到Anaconda Prompt右击进入文件所在位置 2. 右击进入属性 3. 复制cmd.exe开始到最后的路径 cmd.exe "/K" C:\ProgramData\anaconda3\Scripts\activate.bat C:\ProgramData\anaconda3 …

Python语言学习笔记之八(文件IO)

本课程对于有其它语言基础的开发人员可以参考和学习,同时也是记录下来,为个人学习使用,文档中有此不当之处,请谅解。 1、什么是文件I/O 在Python中,文件IO(输人/输出)是指与文件进行交互的过程。这包括读…

JMESPath语言

JMESPath(JSON Matching Expression Path) 一种查询语言。 主要用于从JSON文档中检索和过滤数据。 通过写表达式提取和处理JSON数据,而无需编写复杂的代码。 功能:数据提取、过滤、转换、排序。 场景:处理API响应…

【谭浩强C程序设计精讲 1】数据类型、常量与变量

文章目录 3.1 C 的数据类型3.2 常量与变量3.2.1 常量和符号常量3.2.2 变量 3.1 C 的数据类型 C语言的数据结构是以数据类型形式出现的。C的数据类型如下: C语言中数据有常量与变量之分,它们分别属于以上这些类型。由以上这些数据类型还可以构成更复杂…

三分钟搞定 || java邮件发送(支持附件,多发)

1.添加Maven依赖 <dependency><groupId>com.sun.mail</groupId><artifactId>javax.mail</artifactId><version>1.6.2</version> </dependency><dependency><groupId>cn.hutool</groupId><artifactId>…

图书管理系统jsp + servlet+mysql

图书管理系统 项目使用jsp servletmysql实现&#xff1b; 登陆注册 首页 首页显示图书信息 图书管理 1添加书籍 2查询书籍 3预览书籍 4修改书籍 用户管理 1查询用户 2修改用户 3 删除用户 链接&#xff1a;https://pan.baidu.com/s/1QXK--ypb6OadbmKFlc0jUQ

跨域的解决方式(java后端)

文章目录 一、跨域介绍1、什么是跨域2、为什么会产生跨域3、禁止跨域的原因 二、简单请求和非简单请求1、简单请求1.1、什么时简单请求1.2、简单请求基础流程 2、非简单请求2.1、预检请求2.2、预检请求的回应2.3、浏览器的正常请求和回应 3、自定义跨域过滤器 三、解决方式1、C…

2023年【G2电站锅炉司炉】考试题库及G2电站锅炉司炉考试报名

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 G2电站锅炉司炉考试题库参考答案及G2电站锅炉司炉考试试题解析是安全生产模拟考试一点通题库老师及G2电站锅炉司炉操作证已考过的学员汇总&#xff0c;相对有效帮助G2电站锅炉司炉考试报名学员顺利通过考试。 1、【多…

【Java】智慧工地系统:让建筑行业管理更简单

概述 智慧工地管理平台面向房建、能源、交通各类工地的管理者&#xff0c;通过AI视频、物联感知技术对工地场景中的施工机械、建筑材料、施工规范、施工环境监管、完善施工现场项目管控。实现项目管控、特种设备管理、绿色施工、工地巡检等业务功能&#xff0c;沉淀工地监管数…

IDEA报错处理

问题1 IDEA 新建 Maven 项目没有文件结构 pom 文件为空 将JDK换成1.8后解决。 网络说法&#xff1a;别用 java18&#xff0c;换成 java17 或者 java1.8 都可以&#xff0c;因为 java18 不是 LTS 版本&#xff0c;有着各种各样的问题。。

Web(8)sqlmap工具使用

Sqlmap工具的使用&#xff1a; 首先配置Python环境变量 为什么需要环境变量&#xff1f; 感觉是在cmd中添加了一个快捷方式&#xff0c;使得可以认识 比如path&#xff0c;是告诉系统&#xff0c;当要求系统运行的程序没有告诉程序所在完整路径时&#xff0c;系统除了在当前…

C#浅拷贝和深拷贝数据

目录 一、浅拷贝 二、深拷贝 一、浅拷贝 就是把原来的数据&#xff0c;复制一份&#xff0c;但是2份数据是共享地址的&#xff0c;修改第一份数据或者修改第二份数据&#xff0c;都会一起改变&#xff0c;这可能不是我们程序中需要的场景。 下面我们演示一下&#xff0c;首…

时序预测 | Python实现GRU电力需求预测

时序预测 | Python实现GRU电力需求预测 目录 时序预测 | Python实现GRU电力需求预测预测效果基本描述程序设计参考资料预测效果 基本描述 该数据集因其每小时的用电量数据以及 TSO 对消耗和定价的相应预测而值得注意,从而可以将预期预测与当前最先进的行业预测进行比较。使用该…

MySql的增、删、改、查(MySql数据库学习——五)

增&#xff08;数据添加/插入数据&#xff09; 使用 INSERT INTO SQL 语句来插入数据。我们可以通过 mysql> 命令提示窗口中向数据表中插入数据&#xff0c;或者 通过PHP 脚本来插入数据。 sql语句&#xff1a; INSERT INTO table_name ( field1, field2,...fieldN ) …

暂退法(丢弃法)

在深度学习中&#xff0c;丢弃法&#xff08;Dropout&#xff09;是一种常用的正则化技术&#xff0c;旨在减少模型的过拟合现象&#xff0c;可能会比之前的权重衰减(Weight Decay)效果更好。通过在训练过程中随机丢弃一部分神经元&#xff0c;可以有效地减少神经网络中的参数依…

【华为数据之道学习笔记】5-4 数据入湖方式

数据入湖遵循华为信息架构&#xff0c;以逻辑数据实体为粒度入湖&#xff0c;逻辑数据实体在首次入湖时应该考虑信息的完整性。原则上&#xff0c;一个逻辑数据实体的所有属性应该一次性进湖&#xff0c;避免一个逻辑实体多次入湖&#xff0c;增加入湖工作量。 数据入湖的方式…

如何从 iPhone 上恢复已删除的照片教程分享

您是否错误地删除了 iPhone 上的错误照片&#xff1f;或者您可能已将手机恢复出厂设置&#xff0c;但现在所有照片都消失了&#xff1f;如果您现在遇到这样的情况&#xff0c;我们可以为您提供解决方案。 在本文中&#xff0c;我们将向您展示七种数据恢复方法&#xff0c;可以…

对可恢复的情况使用受检异常

在Java中&#xff0c;受检异常&#xff08;Checked Exception&#xff09;通常用于表示程序能够预期并且可能进行恢复的异常情况。这类异常是在编译时由编译器强制进行处理的&#xff0c;使得程序员必须显式处理这些异常&#xff0c;或者在方法签名中使用 throws 关键字声明。 …