Java(六)——抽象类与接口
文章目录
- 抽象类和接口
- 抽象类
- 抽象类的概念
- 抽象类的语法
- 抽象类的特性
- 抽象类的意义
- 接口
- 接口的概念
- 接口的语法
- 接口的特性
- 接口的使用
- 实现多个接口
- 接口与多态
- 接口间的继承
- 抽象类和接口的区别
抽象类和接口
抽象类
抽象类的概念
Java使用类实例化对象来描述现实生活中的实体,不过,不是所有的类都能描述实体的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类(准确来说,我们可以将这样的类设计成抽象类)。
以画图形为例,有如下代码:
//Shape.java
public class Shape {public void draw() {System.out.println("画一个图形");}
}//Pentagram.java
public class Pentagram extends Shape {@Overridepublic void draw() {System.out.println("五角星☆");}
}//Rotundity.java
public class Rotundity extends Shape {@Overridepublic void draw() {System.out.println("圆形⭕");}
}
我们在实现Shape
类的draw
方法时,由于Shape
是一个宽泛的概念,不是一个具体的图形,所以我们实际上是没办法实现的,上代码中的实现也没有实际的意义,因此,我们可以将Shape
类设计成抽象类,而对于Shape
类中的draw
方法,我们可以将它设计成抽象方法.
抽象类的语法
Java中,被 abstract
修饰的类称为抽象类,抽象类中被 abstract
修饰的方法称作抽象方法。
抽象方法不用给出具体的实现。(这是强制的,不能给出方法体)
将上面的Shape
类设计成抽象类,draw
方法设计成抽象方法:
//Shape.java
public abstract class Shape {public abstract void draw();
}
注意: 抽象类也是类,抽象类也可以有普通的成员方法、成员变量或构造方法。
抽象类与普通类的区别是抽象类有abstract
修饰,且可以存在抽象方法(不存在也可以)。
抽象类的特性
-
抽象类不能实例化对象
public class Test {public static void main(String[] args) {Shape shape = new Shape();//实例化抽象类,报错} }
抽象类虽然不能实例化,但是抽象类的引用可以引用其子类的对象
//Shape.java
public abstract class Shape {public abstract void draw();
}//Pentagram.java
public class Pentagram extends Shape {@Overridepublic void draw() {System.out.println("五角星☆");}
}//Rotundity.java
public class Rotundity extends Shape {@Overridepublic void draw() {System.out.println("圆形⭕");}
}//Test.java
public class Test {public static void func(Shape shape) {shape.draw();}public static void main(String[] args) {Pentagram pentagram = new Pentagram();Rotundity rotundity = new Rotundity();Shape[] shapes = {pentagram, rotundity};//向上转型for(Shape shape : shapes){func(shape);}}
}
-
抽象类必须被继承,且继承抽象类的子类必须重写抽象类中的抽象方法,如果不想重写抽象方法,需要加
abstract
修饰。不过,一旦这个类被一个普通的类继承,则此普通类必须重写所有的抽象方法。public abstract class Test {public abstract void func1(); }abstract class A extends Test {public abstract void func2(); }class B extends A {@Overridepublic void func1() {System.out.println("重写抽象类Test的抽象方法");}@Overridepublic void func2() {System.out.println("重写抽象类A的抽象方法");} }
抽象类
A
继承了抽象类Test
,普通类B
继承了A
,那么普通类B
必须重写A
类和Test
类中的所有抽象方法。 -
由于抽象方法必须被重写,所以抽象方法不能被
private
、final
、static
修饰 -
抽象类中可以不包含抽象方法,但抽象方法必须在抽象类中
public class Test {public abstract void func(); }
-
抽象类中可以存在构造方法,用于子类实例化时初始化父类的成员
//Shape.java public abstract class Shape {public int a;//抽象类的构造方法public Shape(int a) {this.a = a;}public abstract void draw(); }//Pentagram.java public class Pentagram extends Shape {public Pentagram(int a) {super(a);}@Overridepublic void draw() {System.out.println("五角星☆");} }//Rotundity.java public class Rotundity extends Shape {public Rotundity(int a) {super(a);}@Overridepublic void draw() {System.out.println("圆形⭕");} }//Test.java public class Test {public static void main(String[] args) {Shape shape = new Pentagram(20);System.out.println(shape.a);} }
打印结果是:
抽象类的意义
我们可能会有一个疑问,普通类也可以被继承,普通的成员方法也可以被重写,为什么要用抽象类和抽象方法呢?
抽象类中的抽象方法如果没有被重写,编译器会报错。 是的,使用抽象类和抽象方法的好处就是多了一层编译器的校验,能帮助我们检查抽象方法是否被重写。
抽象类不能被实例化。 很多引用场景,比如上面的画图形场景,其实际工作不应该由父类完成,而应由子类完成,此时误用父类编译器会报错。
总的来说,使用抽象类就是为了预防出错,并让我们尽早发现问题,充分利用编译器的校验,在实际开发中是非常有意义的。
接口
接口的概念
接口(英文:Interface),在JAVA编程语言中是一个抽象(引用)类型,是抽象方法的集合。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
我们很容易联想到实际生活中电脑的USB接口,它是一个标准,符合这个标准,就可以与电脑交互(可以插U盘、鼠标等)。
Java中的接口也是公共行为的规范,我们在实现时,只要符合标准,就可以通用。所以,接口可以看作是:多个类的公共规范,是一种引用类型
接口的语法
接口的定义与类的定义类似,只需要把关键字class
换成interface
接口只能被public
、abstract
修饰,abstract
默认不显性显示,如果省略public
则使用默认的访问权限
public interface 接口名 {//...
}
- 接口的命名一般是以
I
开头 - 接口的命名一般使用形容词词性的单词,这样就能显示出接口的标准
接口的特性
-
接口是一种引用类型,但是不能直接实例化对象(接口实际上比抽象类更加抽象),不过接口可以引用实现该接口的类的对象(向上转型)
public static void main(String[] args) {ITest iTest = new ITest();//报错,不能直接实例化接口}
interface ITest {//待实现的方法void func(); }class A implements ITest {@Overridepublic void func() {System.out.println("类A实现的func");} }class NewTest {public static void main(String[] args) {//接口引用了A类对象ITest iTest = new A();} }
-
接口可以定义变量,且接口的成员变量都是
public
、static
、final
修饰的,且接口定义的变量必须手动初始化即使我们不写修饰符,成员变量也默认被
public
、static
、final
修饰public abstract interface ITest {//下面定义的变量都是由 public static final 修饰的(不论是否显性书写或写全)public int a = 1;static int b = 2;final int c = 3;int d = 4;public static int e = 5;static final int f = 6;public final int g = 7;public static final int h = 8; }
-
接口可以定义方法,接口的方法默认是
public
、abstract
修饰的,属于抽象方法,不需要方法体。如果想要在接口中具体实现一个方法,那么它必须是由default
或static
修饰public interface ITest {//以下写法的修饰符都是 public abstract(无论是否写或写全)void func0();public abstract void func1();public void func2();abstract void func3();//被default或static修饰的方法有具体的实现default void func4() {System.out.println("接口中被default修饰的方法有方法体");}static void func5() {System.out.println("接口中被static修饰的方法有方法体");} }
-
实现接口的类,必须重写接口中的所有抽象方法,如果此类不想重写接口中的抽象方法,则它必须由
abstract
修饰,一旦此类被另一个非抽象类继承,那么这个非抽象类必须重写所有未被重写的抽象方法interface IA {//接口抽象方法void abfunc1(); }abstract class A implements IA {public void myA() {System.out.println("A类特有的方法");}//A类抽象方法abstract void abfunc2(); }class B extends A {@Overridepublic void abfunc1() {System.out.println("重写IA接口中的抽象方法");}@Overridevoid abfunc2() {System.out.println("重写B类中的抽象方法");} }
-
接口中不能有静态代码块、构造代码块或构造方法
-
由于接口的成员方法默认都有
public
修饰,所以重写后的方法必须是public
修饰(重写后的方法的访问权限要大于等于父类) -
上述表述的重写严格来说不准确,不过,语法要求与重写一致(这里不必纠结,只要记住抽象方法要被重写即可)
-
接口文件的文件名必须与接口名相同,且接口文件编译后也是
.class
为后缀的字节码文件
接口的使用
接口不能直接实例化对象,接口的使用需要一个 “实现类” 来 实现 接口中的方法,要用到关键字implements
public class 类 implements 接口 {//...
}
接口与类之间implements
是实现关系,父类和子类之间extends
是继承关系
interface ITest {//待实现的方法void func();
}class A implements ITest {@Overridepublic void func() {System.out.println("类A实现的func");}
}
继承表达的是is A
的关系,如狗是动物;接口表达的含义是具有xxx特性
,如狗会跑
实现多个接口
Java中不支持多继承,不过一个类可以实现多个接口,这个类需要实现所有接口的抽象方法:
//ISwimming.java
public interface ISwimming {void swim();
}//IRunning.java
public interface IRunning {void run();
}//Dog.java
public class Dog implements IRunning, ISwimming {public String name;public int age;public Dog(String name, int age) {this.name = name;this.age = age;}@Overridepublic void run() {System.out.println(this.name + "正在跑");}@Overridepublic void swim() {System.out.println(this.name + "正在游泳");}
}
- 一个类实现多个接口时,每个接口中的抽象方法都要实现,否则类必须设置为抽象类
一个类可以继承一个父类并同时实现多个接口:
//Animal.java
public class Animal {public String name;public int age;
}
//IRunning.java
public interface IRunning {void run();
}//ISwimming.java
public interface ISwimming {void swim();
}//Dog.java
public class Dog extends Animal implements IRunning, ISwimming {public Dog(String name, int age) {this.name = name;this.age = age;}@Overridepublic void run() {System.out.println(this.name + "正在跑");}@Overridepublic void swim() {System.out.println(this.name + "正在游泳");}
}
- 继承与实现都存在时,必须先写
extends
继承,后写implements
实现 - 对于上面的代码,理解一点:只要一个类实现了如
IRunning
接口,它就可以run()
,而不必是动物。(有些废话,主要是强调接口使用)
接口与多态
Java中,接口可以实现多态,看如下代码:
//IEat.java
public interface IEat {void eat();
}//Animal.java
public class Animal {public String name;public int age;
}//Cat.java
public class Cat extends Animal implements IEat {public Cat(String name, int age) {this.name = name;this.age = age;}@Overridepublic void eat() {System.out.println(this.name + "正在吃猫粮...");}
}//Dog.java
public class Dog extends Animal implements IEat {public Dog(String name, int age) {this.name = name;this.age = age;}@Overridepublic void eat() {System.out.println(this.name + "正在吃狗粮...");}
}//Test.java
public class Test {//体现多态public static void testEat(IEat iEat) {iEat.eat();}public static void main(String[] args) {testEat(new Dog("大哈", 2));//匿名对象testEat(new Cat("小猫", 3));}
}
对于上述代码,我们给同一个方法testEat
传入不同的对象Cat
和Dog
,打印结果不同:
接口间的继承
接口的继承相当于把所有的接口合并在一起。
接口间可以实现继承
//IExcellentQuality.java
public interface IExcellentQuality {void func1();
}//IKind.java
public interface IKind extends IExcellentQuality {void func2();
}
上述代码逻辑上就是:善良的 是 品质优良的
-
一个接口继承了另一个接口,子接口不实现父接口的抽象方法,而当一个非抽象类实现了子接口,那么这个类要重写子接口和父接口所有的抽象方法
public class Person implements IKind {@Overridepublic void func2() {System.out.println("kind");}@Overridepublic void func1() {System.out.println("excellent quality");} }
Java中,类与类之间不可以实现多继承,但接口与接口之间可以实现多继承
比如以下例子,两栖动物既可以游泳又可以行走:
//IRunning.java
public interface IRunning {void run();
}//ISwimming.java
public interface ISwimming {void swim();
}//IAmphibious.java
public interface IAmphibious extends ISwimming, IRunning {void func();
}
【总结】
- 一个接口继承了另一个接口,子接口不实现父接口的抽象方法,而当一个非抽象类实现了子接口,那么这个类要重写子接口和父接口所有的抽象方法
- 接口与接口之间可以实现多继承
抽象类和接口的区别
抽象类中可以包含普通的方法和字段,这些字段和方法可以被子类直接使用(普通方法不需要被重写),而接口中不能定义普通的字段和方法,子类必须重写接口中的所有抽象方法。
几点具体的区别:
-
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行(除非被
default
或static
修饰)。
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行(除非被
-
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
-
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。(从
Java8
开始接口中可以定义静态方法)
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。(从
-
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
另外,我们补充一下实现接口与继承的区别:
1.不同的关键字,即实现接口(implements),继承(extends);
2.(一个类只能继承一个父类,而一个方法可以实现多个接口) 在面向对象编程的时候只能是单继承,但是实现接口可以有多个,简单点说,就是实现接口可以有好多个,但是继承的中父类只能只有一个,因为父亲只有一个,这说明了继承在Java中具有单根性,子类只能去继承一个父类;
3.在接口中只能定义全局变量和抽象方法,而在继承中可以定义普通的属性、方法等等…
4.(接口中的抽象方法必须被重写,而继承中子类可以选择不重写父类的方法(不考虑父类是抽象类)) 当某个接口被实现的时候,在类中一定要重写接口中的抽象方法,而继承中子类可以选择是否重写父类的方法,不是强制的
以上就是对Java中抽象类和接口的所有介绍了,希望能给大家带来帮助!
接下来将会发布不少博客:Java实现简单的图书管理系统、介绍内部类、介绍String…
相关文章:

Java(六)——抽象类与接口
文章目录 抽象类和接口抽象类抽象类的概念抽象类的语法抽象类的特性抽象类的意义 接口接口的概念接口的语法接口的特性接口的使用实现多个接口接口与多态接口间的继承抽象类和接口的区别 抽象类和接口 抽象类 抽象类的概念 Java使用类实例化对象来描述现实生活中的实体&…...

【4.vi编辑器使用(下)】
一、vi编辑器的光标移动 二、vi编辑器查找命令 1、命令::/string 查找字符串 n:继续查找 N:反向继续查找 /^the 查找以the开头的行 /end 查找以 查找以 查找以结尾的行 三、vi编辑器替换命令 1、语法: : s[范围,范围]str1/str2[g] g表示全…...

【数据结构】探索树中的奇妙世界
专栏介绍: 哈喽大家好,我是野生的编程萌新,首先感谢大家的观看。数据结构的学习者大多有这样的想法:数据结构很重要,一定要学好,但数据结构比较抽象,有些算法理解起来很困难,学的很累…...

搭建YOLOv10环境 训练+推理+模型评估
文章目录 前言一、环境搭建必要环境1. 创建yolov10虚拟环境2. 下载pytorch (pytorch版本>1.8)3. 下载YOLOv10源码4. 安装所需要的依赖包 二、推理测试1. 将如下代码复制到ultralytics文件夹同级目录下并运行 即可得到推理结果2. 关键参数 三、训练及评估1. 数据结构介绍2. 配…...

c++(一)
c(一) C与C有什么区别命名空间使用 输入输出流引用指针和引用的区别定义拓展 函数重载例子测试函数重载原理 参数默认值什么是参数默认值注意 在c中如何引入c的库动态内存分配new、delete与malloc、free的区别? C与C有什么区别 <1>都是…...
java面试中高频问题----1
一、乐观锁和悲观锁定义、场景怎么判断用什么? 1.乐观锁: 定义:乐观锁假设大多数情况下,资源不会发生冲突。因此,允许多个线程同时访问资源。 场景:读操作多,写操作少,数据冲突概率…...

ABB 控制柜
1,主计算机:相当于电脑的主机,用于存放系统和数据,需要24V直流电才能工作。执行用户编写的程序,控制机器人进行响应的动作。主计算机有很多接口,比如与编程PC连接的服务网口、用于连接示教器的网口、连接轴…...

【错误记录】HarmonyOS 运行报错 ( Failure INSTALL_PARSE_FAILED_USESDK_ERROR )
文章目录 一、报错信息二、问题分析三、解决方案 一、报错信息 在 DevEco Studio 中 , 使用 远程设备 , 向 P40 Failure[INSTALL_PARSE_FAILED_USESDK_ERROR] compileSdkVersion and releaseType of the app do not match the apiVersion and releaseType on the device. 二、…...

使用C语言openssl库实现 RSA加密 和 消息验证
Q:什么是RSA? A:RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,是最早的一种用于公开密钥加密和数字签名的算法。它使用一对公钥(public key)和私钥(private key&…...
海外投放面试手册
海外投放面试手册 岗位职责: 负责Google 、Facebook、TikTok、Twitter等海外主流广告平台的自主投放操作及合作渠道沟通;负责海外合作渠道媒体的广告投放管理、媒体数据监测、效果分析、优化调整等工作; 3.了解海外各渠道&…...

第十三章 进程与线程
第十三章 进程与线程 程序与进程的概念 程序: 英文单词为Program,是指一系列有序指令的集合,使用编程语言所编写,用于实现一定的功能。 进程: 进程则是指启动后的程序,系统会为进程分配内存空间。 函数式…...
Flink面试整理-对Flink的高级特性如CEP(复杂事件处理)、状态后端选择和调优等有所了解
Apache Flink 提供了一系列高级特性,使其成为一个强大的实时数据处理框架,特别适用于复杂的数据处理场景。其中,复杂事件处理(CEP)、状态后端的选择和调优是其中重要的几个方面。 复杂事件处理(CEP) CEP 概念:CEP 是用于在数据流中识别复杂模式的技术。它允许用户指定事…...

算法:树状数组
文章目录 面试题 10.10. 数字流的秩327. 区间和的个数315. 计算右侧小于当前元素的个数 树状数组可以理解一种数的存储格式。 面试题 10.10. 数字流的秩 假设你正在读取一串整数。每隔一段时间,你希望能找出数字 x 的秩(小于或等于 x 的值的个数)。 请实现数据结构…...

Kafka SASL_SSL集群认证
背景 公司需要对kafka环境进行安全验证,目前考虑到的方案有Kerberos和SSL和SASL_SSL,最终考虑到安全和功能的丰富度,我们最终选择了SASL_SSL方案。处于知识积累的角度,记录一下kafka SASL_SSL安装部署的步骤。 机器规划 目前测试环境公搭建了三台kafka主机服务,现在将详…...

同城交友论坛静态页面app Hbuild
关注...
spring session+redis存储session,实现用户登录功能,并在拦截器里面判断用户session是否过期,过期就跳转到登录页面
在Spring应用中,使用Redis存储Session是一种常见的方式,可以实现分布式环境下的Session管理。以下是实现用户登录功能,并在拦截器中判断Session是否过期并跳转到登录页面的基本步骤: 添加依赖:首先,确保你的…...
Debug-013-el-loading中显示倒计时时间
前言: 今天实现一个小小的优化,业务上是后端需要从设备上拿数据,所以前端需要不断调用一个查询接口,直到后端数据获取完毕,前后端根据一个ending字段为true判断停止调用查询接口。由于这个查询时间比较久&…...
5月29日,每日信息差
第一、据悉,微信视频号直播电商团队将并入到微信开放平台(小程序、公众号等)团队,原微信视频号直播电商团队转由微信开放平台负责人负责。知情人士表示,此次调整,将有助于微信视频号直播电商业务更好地融入…...

2024年弘连网络FIC大会竞赛题线下决赛题
总结: FIC决赛的时候,很多小问题没发现,在pve平台做题确实很方便。 这套题目复盘完,服务器这块的知识确实收获了很多,对pve集群平台和网络拓扑也有了一定的认识,感谢各位大佬悉心指导。 接下来࿰…...

Element-UI 入门指南:从安装到自定义主题的详细教程
Element-UI 是一个基于 Vue.js 的前端组件库,它提供了丰富的 UI 组件,可以帮助开发者快速构建高质量的用户界面。以下是使用 Element-UI 的快速入门指南: 安装 Element-UI Element-UI 是一个基于 Vue.js 的组件库,它提供了丰富的…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...