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{@Overridepublic void Testa() {System.out.println("B重写的testa方法");}@Overridepublic 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{@Overridepublic void openDevice() {System.out.println("打开鼠标");}public void click(){System.out.println("疯狂点击鼠标");}@Overridepublic void closeDevice() {System.out.println("关闭鼠标");}
}
class KeyBoard implements USB{@Overridepublic void openDevice() {System.out.println("打开键盘");}public void input(){System.out.println("疯狂打字");}@Overridepublic 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);}@Overridepublic void run() {System.out.println("正在用囧囧跑步步");}@Overridepublic void eat() {System.out.println("吃狗粮");}
}
class Flog extends Animal implements Running,Swimming{@Overridepublic void run() {System.out.println("正在用俩只大脚掌跑步步");}@Overridepublic void swim() {System.out.println("正在用那小手手游泳");}public Flog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("吃蛙粮");}
}
class Duck extends Animal implements Running,Flying,Swimming{@Overridepublic void run() {System.out.println("正在小跑");}@Overridepublic void swim(){System.out.println("正在划水");}@Overridepublic void fly() {System.out.println("正在扇翅膀飞飞");}public Duck(String name, int age) {super(name, age);}@Overridepublic 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 {@Overridepublic void testC() {}@Overridepublic void testA() {}@Overridepublic 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语言中指针的指向)。

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

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

相关文章

常用模块之(time/datetime)

【 一 】时间模块(time/datetime) 【 二 】 表示时间的三种方式 *时间戳(Timestamp)是指1970年1月1日00:00:00开始计算的偏移量。可以使用time模块中的time()函数获取当前时间的时间戳,也可以使用datetime模块中的tim…

大创项目推荐 深度学习 python opencv 实现人脸年龄性别识别

文章目录 0 前言1 项目课题介绍2 关键技术2.1 卷积神经网络2.2 卷积层2.3 池化层2.4 激活函数:2.5 全连接层 3 使用tensorflow中keras模块实现卷积神经网络4 Keras介绍4.1 Keras深度学习模型4.2 Keras中重要的预定义对象4.3 Keras的网络层构造 5 数据集处理训练5.1 …

ElasticSearch学习篇8_Lucene之数据存储(Stored Field、DocValue、BKD Tree)

前言 Lucene全文检索主要分为索引、搜索两个过程,对于索引过程就是将文档磁盘存储然后按照指定格式构建索引文件,其中涉及数据存储一些压缩、数据结构设计还是很巧妙的,下面主要记录学习过程中的StoredField、DocValue以及磁盘BKD Tree的一些…

PyQt6 QScrollBar滚动条控件

锋哥原创的PyQt6视频教程: 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计48条视频,包括:2024版 PyQt6 Python桌面开发 视频教程(无废话版…

录制第一个jmeter性能测试脚本2(http协议)_图书管理系统

我们手工编写了一个测试计划,现在我们通过录制的方式来实现那个测试计划。也就是说‘’测试计划目标和上一节类似:让5个用户在2s内登录图书管理系统,然后进入 页面进行查看。 目录 欢迎访问我的免费课程 PPT、安装包、视频应有尽有&#xff…

【微服务】Spring Aop原理深入解析

目录 一、前言 二、aop概述 2.1 什么是AOP 2.2 AOP中的一些概念 2.2.1 aop通知类型 2.3 AOP实现原理 2.3.1 aop中的代理实现 2.4 静态代理与动态代理 2.4.1 静态代理实现 三、 jdk动态代理与cglib代理 3.1 jdk动态代理 3.1.1 jdk代理示例 3.1.2 jdk动态代理模拟实现…

【OpenCV】 OpenCV 源码编译并实现 CUDA 加速 (Windows)

OpenCV 源码编译并实现 CUDA 加速 Windows 1. 环境准备1.1 软件环境1. 2 源码下载 2. CMake编译项目2.1 创建cmake项目2.2 设置编译配置2.3 解决异常2.3.1 文件下载异常2.3.2 解决CUDA版本异常 2.4 编译项目 3. Visual Studio 编译项目4. 项目测试5. 总结 OpenCV是一个基于Apac…

Ubuntu 常用命令之 ln 命令用法介绍

ln命令在Ubuntu系统中用于创建硬链接或符号链接。硬链接是指向文件的物理地址,而符号链接(也称为软链接)是指向文件路径的引用。 命令格式:ln [选项]... [-T] 目标(源文件) 链接(目标文件&…

【FPGA】Verilog:编码器 | 实现 4 到 2 编码器

0x00 编码器(Encoder) 编码器与解码器相反。当多台设备向计算机提供输入时,编码器会为每一个输入生成一个与设备相对应的信号,因此有多少比特就有多少输出,以数字形式表示输入的数量。 例如,如果有四个输…

NAS搭建WebDAV服务同步Zotero科研文献

文章目录 一、Zotero安装教程二、群晖NAS WebDAV设置三、Zotero设置四、使用公网地址同步Zotero文献库五、使用永久固定公网地址同步Zotero文献库 Zotero 是一款全能型 文献管理器,可以 存储、管理和引用文献,不但免费,功能还很强大实用。 ​ Zotero 支…

重新认识Word——尾注

重新认识Word——尾注 参考文献格式文献自动生成器插入尾注将数字带上方括号将参考文献中的标号改为非上标 多处引用一篇文献多篇文献被一处引用插入尾注有横线怎么删除?删除尾注 前面我们学习了如何给图片,公式自动添加编号,今天我们来看看毕…

LSTM ——作业

习题6-4 推导LSTM网络中参数的梯度, 并分析其避免梯度消失的效果 习题6-3P 编程实现下图LSTM运行过程 1. 使用Numpy实现LSTM算子 import numpy as np # 创建一个numpy数组x,它是一个4x4的矩阵,包含9个元素 x np.array([[1, 0, 0, 1],[3, …

Unity中URP下的菲涅尔效果实现(URP下的法线和视线向量怎么获取)

文章目录 前言一、实现思路二、实现原理我们可以由下图直观的感受到 N 与 L夹角越小,点积越接近(白色)1。越趋近90,点积越接近0(黑色) 三、实现URP下的菲涅尔效果1、我们新建一个Shader,修改为最…

安全密码(字符串)

#include <stdio.h> #include <stdbool.h> #include <string.h> bool is_secure_password(const char* password); int main() {int M;char password[51];// 读取输入中的密码数量 Mscanf("%d", &M);// 处理每个密码for (int i 0; i < M; …

Pytorch:Tensorboard简要学习

目录 一、TensorBoard简介二、TensorBoard的安装与启动Tensorboard的安装Tensorboard的启动 三、TensorBoard的简单使用3.1 SummaryWriter()3.2 add_scalar()和add_scalars()3.3 add_histogram()3.4 模型指标监控 四、总结参考博客 一、TensorBoard简介 TensorBoard 是Google开…

17.Oracle中instr()函数查询字符位置

1、instr()函数的格式 &#xff08;俗称&#xff1a;字符查找函数&#xff09; 格式一&#xff1a;instr( string1, string2 ) // instr(源字符串, 目标字符串) 格式二&#xff1a;instr( string1, string2 [, start_position [, nth_appearance ] ] ) // instr(源字符…

typescript使用解构传参

看下面这个函数 interface Student {id: number;name: string;class: string;sex: string;}function matriculation(student: Student) {//...}我们要调用它,就需要传递一个实现了Student约束的对象进去 interface Student {id: number;name: string;class: string;sex: string…

C语言:将三个数从大到小输出

#include<stdio.h> int main() {int a 0;int b 0;int c 0;printf("请输入abc的值&#xff1a;");scanf_s("%d%d%d", &a, &b, &c);if (b > a){int tmp a;a b;b tmp;}if (c > a){int tmp a;a c;c tmp;}if (b < c){int t…

app分发平台哪个好点?手机app应用内测分发平台支持负载均衡的重要性

随着互联网的快速发展&#xff0c;内测分发平台扮演着越来越重要的角色。而在现代应用程序的开发和运营过程中&#xff0c;负载均衡技术是不可或缺的一部分。内测分发平台支持负载均衡对于提高系统的稳定性、可靠性和性能至关重要。那么什么是负载均衡又有哪些重要性。 图片来源…

在线学习平台,云课堂云教育类网站源码,在线题库+随身携带的刷题神器+视频安装教程

源码介绍 在线题库&#xff1a;由传统的线下学习模式改为在线学习。能够实现学员在线学习、练习、考试 优点&#xff1a;方便、便宜、自我管理、选择性更多 、成人教育 &#xff08;1&#xff09;公考&#xff1a;国考、省考、事业单位… &#xff08;2&#xff09;升学&…