- 博主简介:努力学习的预备程序媛一枚~
- 博主主页: @是瑶瑶子啦
- 所属专栏: Java岛冒险记【从小白到大佬之路】
文章目录
- 一、抽象类
- 1.1:抽象类的概念
- 1.2:抽象类的定义
- 1.3:抽象类的特性
- 1.4:抽象类的作用和意义
- 二、接口
- 引入
- 2.1、简介
- 2.2、接口的定义
- 2.2.1:接口内部语法
- 2.3、接口的实现
- 2.3.1:普通类实现接口
- 2.3.2:抽象类实现接口
- 2.4、接口的多态
- 2.5、接口之间继承
- 2.6、接口使用场景
- 2.7、接口的特性(使用细节)
- 2.8:接口存在的意义
- 三、抽象类和接口的区别和联系
一、抽象类
1.1:抽象类的概念
我们知道,可以通过类实例化一个对象。为什么呢?因为我们可以通过这个类中的属性和方法具体描述这个对象。
但是,不是所有的类都可以具体描述一个对象
🙋🏼♀️何为 “具体描述” ???
看下面这个例子:
class Shape {
public void draw() {
}
public void getArea() {
}
protected double area;
}
//矩形类
class Rect extends Shape {
private final double length;
private final double width;
public Rect(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public void draw() {
System.out.println("矩形:length = " + length + "width = " + width);
}
@Override
public void getArea() {
area = length * width;
}
}
//圆形类
class Circle extends Shape {
private final double r;
final private double PI = 3.14;
public Circle(double r) {
this.r = r;
}
@Override
public void draw() {
System.out.println("圆形:半径r = " + r);
}
@Override
public void getArea() {
area = PI * r * r;
}
}
public class Main {
public static void main(String[] args) {
}
}
很明显,
Shape
类不能具体的描述一个对象(长?宽?面积?),不能将它实例化。像这样抽象的类,我们要定义成抽象类。
接下来我们看看抽象类的定义:
1.2:抽象类的定义
- 抽象类要被
abstract
修饰 - 抽象类中的抽象方法(没有方法体的)也要被
abstract
修饰 - 抽象类的本质也是类,可以像普通类一样有普通方法和属性
abstract class Shape {
abstract public void draw();
protected double area;
public double getArea() {
return area;
}
}
1.3:抽象类的特性
- 抽象类不能直接实例化对象
- 抽象类的本质也是类,可以拥有成员方法&成员变量
- 抽象方法不能为
private
,且不能被final
和static
修饰,因为子类必须要重写父类中的抽象方法 - 抽象类被继承有两种情况
- 子类重写该抽象类中的所有抽象方法,该类和普通类则一样,可以被实例化
- 子类重写该抽象类中的部分抽象方法,则该类仍然是一个抽象类,无法被实例化,且必须被
abstract
修饰
- 抽象类中可以有构造方法,作用是:子类创建对象时调用父类构造方法来初始化父类的成员变量
- 抽象类中不一定包含抽象方法,但是有抽象方法的一定是抽象类
1.4:抽象类的作用和意义
💁🏻♀️有的人可能会想,抽象类存在的意义是什么呢?就像开头给出的那段代码那段例子,我们的确无法写出Shape
类中的getArea
那两个方法的方法体,那我们就空着不久行啦?为什么还要这么麻烦,定义抽象类和抽象方法呢???
引入抽象类,其实是Java提供一种语法工具,作用是引导和规范使用者正确的使用她们,减少误用。
使用抽象类,类使用者在创建对象时,就不会误用不完整的抽象父类实例化进行实例化(编译器会报错),就知道必须使用某个具体的子类来进行实例化。且子类继承是,就要求必须实习其抽象方法,而不可能忽略。
二、接口
引入
对于类,是具体事物抽象而成。类的概念强调类型。但是在解决问题的大多数情况下,我们并不强求一定需要某个类型。为什么这么说呢?
比如我们现在的需求是:拍照。那我们可以用手机、相机…只要能满足拍照功能的即可,我们不在意是什么类型,而是在意此事物是否有此功能,有就来。
在很多情况下就是如此,类型不重要,重要的是能力。
Java中用一种扩展类-----接口(interface)来显现能力。今天,瑶瑶子带大家系统学习一下Java中的接口。
2.1、简介
简单来说,接口就是声明一组能力的类。接口内部声明了很多方法(一般是抽象),也就是功能,但接口本身不去做实现(每个类型的实现方法本就不同,没有必要去实现)。当 实现(implements) 了该接口,就证明这个类,拥有了该接口中声明的方法(即能力)。这样,就达到了表示能力的目的。
2.2、接口的定义
接口的定义,和类的定义十分相似:
interface SendMessage {
public static final String MSG = "yaoyao";
public abstract void print();
}
1. 使用interface
关键字来定义一个接口(与类的定义对比:将class换成了interface)
2. 接口的修饰符只能是public
和默认
,这点和普通类是一样的
3. 接口命名,一般以大写字母I
开头
4. 接口命名一般以形容词
词性单词(表示能力嘛~
2.2.1:接口内部语法
和类相似,接口内部也可定义属性和方法。但对于属性和方法的声明定义,有一定的语法规则。
- 属性
- public static final 变量类型 变量名
前三个关键字可省略
不写,默认就是它们;注意,因为是常量,所以接口中的属性必须显示初始化
- public static final 变量类型 变量名
- 方法
- JDK8以前:public abstract 返回类型 方法名();
前两个关键字可省略
- JDK 8以后: 新增了两种可以有方法体的方法:
- 默认方法: default public 修饰;
默认方法必须有默认的方法实现.实现接口的子类可以选择重写,也可以选择不重写.(该方法存在的意义在于:便于给接口增加功能,而又不影响子类,否则增加一个默认为抽象的方法,子类必须重写,这样封装性不好,耦合性也高) - 静态方法: public static 修饰
可以直接使用接口名.方法名(参数列表)
调用
- 默认方法: default public 修饰;
- JDK8以前:public abstract 返回类型 方法名();
阿里编程规范中,接口的属性和方法不要加任何修饰符(因为上面说了,默认就有的,可以省略
2.3、接口的实现
上面提到,接口的本身其实就是声明一些功能,单单有接口,这不是接口设计的初衷.
接口设计的初衷就是将接口也和类一样,作为一个Subtype
(超类),供其他类去实现(拥有功能).
接口不能实例化,必须有一个“实现类”来实现接口,实现接口中的所有抽象方法。
那如何去实现接口呢?
2.3.1:普通类实现接口
eg:Computer类实现SendMessage接口和MyCompare接口
interface SendMessage {
public static final String MSG = "yaoyao";
public abstract void print();
}
interface MyCompare {
public int compare (Object otherObj);
}
class Computer implements SendMessage, MyCompare {
String useName;
int innerStorage;
@Override
public void print() {
System.out.println(this.useName + "正在发送信息:" + MSG);
}
@Override
public int compare(Object otherObj) {
if (!(otherObj instanceof Computer)) {
throw new IllegalArgumentException();
}
Computer otherCom = (Computer) otherObj;
return this.innerStorage - otherCom.innerStorage;
}
}
代码解释如下:
-
implements
表示实现某个接口.前面是子类名,后面是要实现的接口的接口名 -
一个子类可以实现多个接口,接口名之间用英文逗号
,
分隔 -
普通类实现接口,在该类中必须全部重写实现的接口中定义的抽象方法
2.3.2:抽象类实现接口
一般来说,是普通类实现接口比较常见,但是由于普通类实现接口必须必须重写接口中所有抽象方法,这样在一些情况下会造成代码冗余.
由此,抽象类来实现接口就可以很好的解决这一问题,因为抽象类可以选择性的实现接口中的抽象方法.——实现接口中的部分抽象方法
这样一来,可以让抽象类来实现一部分常用的方法,剩下一部分让子类自己实现,来简化书写.
(ps:但是继承了一个类,就不能继承其他类了,这又是基于Java单继承模式的让普通类继承抽象类的弊端)
2.4、接口的多态
一个类的父类和这个类实现的所有接口都称为超类型(Supertype),而这个类称为该超类型的子类型(Subtype).
子类型对象的引用,可以被超类型引用变量接收,这就是对象的多态性!
和之前在多态那篇文章【Java】弄清多态,看这一篇就够了|由浅入深,保姆级详解中几乎差不多,只是那里是以普通类的父类为例,讲的多态,这里是接口.这里也就不重复造轮子了.
主要就是:
- 接口类型引用可以指向实现接口的子类型对象
Interface A{
}
class B implements A {
}
Interface interface = new B();
这里再讲一点不同的:多态传递:接口可以继承接口,父接口的引用也可以指向实现子接口的普通类的对象.
public class Demo {
public static void main(String[] args) {
B b = new Son();
A a = new Son();//OK!
}
}
interface A {
}
interface B extends A {
}
class Son implements B {
}
💁🏻♂️接口多态的意义: 让程序员“忘记”类型。类的使用者就不用关注具体类型,而只关注某个类是否具有某种功能!
2.5、接口之间继承
在上面我讲到,接口可以继承接口,这和类的继承是相似的。有以下需要注意的点:
- 不存在子接口内实现父接口中抽象方法的说法(上面已经讲到,作为接口,其中包含的方法只有那么几种)
- 若非抽象子类只是实现了父接口,只用重写父接口中的抽象方法
- 若非抽象子类实现了子接口,父接口中和子接口中的抽象方法都必须被实现
- 和类不同的是,一个接口可以继承多个父接口,中间用英文逗号分隔即可
- 父接口的引用也可以指向实现子接口的普通类的对象(多态)
//一个接口可以继承多个父接口举例:
Interface A{
void method01();
}
Interface B{
void method02();
}
Interface C extends A,B {
}
其实于其叫作接口的继承,不如取extends
本身意思,“扩展”.即接口的扩展。时B接口同时扩展了A接口中的功能。
意义
- 代码复用
- 扩展功能
- 解耦
2.6、接口使用场景
当我们,只关心实现功能时(需要实现的功能已经确定),具体用什么类型来实现,并不想具体去操心
以下是利用接口和接口多态的一个小案例:模拟数据库的连接
体会接口的好处
数据库接口:
//src.com.yaoyao
package com.yaoyao;
public interface DBInterface {
public void connect();
public void close();
}
不同的数据库子类:MysqlDB\OracleDB
package com.yaoyao;
public class MysqlDB implements DBInterface{
@Override
public void connect() {
System.out.println("连接Mysql数据库");
}
@Override
public void close() {
System.out.println("关闭Mysql数据库连接");
}
}
package com.yaoyao;
public class OracleDB implements DBInterface{
@Override
public void connect() {
System.out.println("连接Oracle数据库");
}
@Override
public void close() {
System.out.println("关闭Oracle数据库连接");
}
}
使用接口作为参数设计(多态的体现—>解耦)
解释:这样,fun函数的功能就是连接和关闭数据库,只要具备该功能(即实现了DBInterface接口),就可以传进来
package com.yaoyao;
public class InterfaceDemo {
public static void main(String[] args) {
MysqlDB mysqlDB = new MysqlDB();
fun(mysqlDB);
}
public static void fun(DBInterface db){
db.connect();
db.close();
}
}
2.7、接口的特性(使用细节)
这里就官方给出的解释基础上,还添加汇总一些接口使用细节和注意事项
An interface declaration defines a new interface that can ①be implemented by one or more classes. Programs can use interfaces to ②provide a common supertype for otherwise unrelated classes, and to ③make it unnecessary for related classes to share a common abstract superclass.
Interfaces ④have no instance variables, and ⑤typically declare one or more abstract methods; ⑥otherwise unrelated classes can implement an interface by providing implementations for its abstract methods. Interfaces may not be directly instantiated.
-
①一个接口可以被多个类实现(同时,一个类也可以实现多个接口)
-
②接口的作用相当于给没有关系的类,提供了一个超类型
理解:比如相机、手机,没有很必然的关系,但是它们都实现了拍照这个接口,它们都具有拍照的功能。这个拍照接口,类似于是它们的超类型(superType
)。注意,这里不是is-a
的那个父类。你不能说手机是拍照把? -
③接口的实现,让相关类不必再共享同一个抽象超类
-
④ 接口不可被实例化
-
⑤接口中通常声明一个或多个抽象方法
-
⑥无关的类们可以通过实现接口中的抽象方法来实现接口
-
⑦接口不可继承普通类,但接口可继承接口
2.8:接口存在的意义
类的使用者就不用关注具体类型,而只关注某个类是否具有某种功能!
三、抽象类和接口的区别和联系
区别 | 抽象类(abstract) | 接口(interface) | |
---|---|---|---|
1 | 结构组成 | 普通类+抽象方法 | 全局常量+抽象方法+默认方法+ 静态方法 |
2 | 子类使用 | 使用extends 关键字,继承抽象类 | 使用implements 关键字实现接口 |
3 | 关系 | 一个抽象类可以实现若干接口 | 接口不能继承抽象类,但是接口可以使用extends 扩展多个接口 |
4 | 子类限制 | 一个子类只能继承一个抽象类 | 一个类可以实现多个接口 |
🫐抽象类和接口配合而非替代的关系。一个类通常有一个抽象类,该抽象类提供默认实现,实现全部或部分方法;可以实现多个接口,表示有多种功能!
-
Java岛冒险记【从小白到大佬之路】
-
LeetCode每日一题–进击大厂
-
Go语言核心编程
-
算法