- 博主简介:努力学习的预备程序媛一枚~
- 博主主页: @是瑶瑶子啦
- 所属专栏: Java岛冒险记【从小白到大佬之路】
我们知道,可以通过类实例化一个对象。为什么呢?因为我们可以通过这个类中的属性和方法具体描述这个对象。
但是,不是所有的类都可以具体描述一个对象
♀️何为 “具体描述” ???
看下面这个例子:
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
类不能具体的描述一个对象(长?宽?面积?),不能将它实例化。像这样抽象的类,我们要定义成抽象类。
接下来我们看看抽象类的定义:
abstract
修饰abstract
修饰abstract class Shape {
abstract public void draw();
protected double area;
public double getArea() {
return area;
}
}
private
,且不能被final
和static
修饰,因为子类必须要重写父类中的抽象方法abstract
修饰 ♀️有的人可能会想,抽象类存在的意义是什么呢?就像开头给出的那段代码那段例子,我们的确无法写出Shape
类中的getArea
那两个方法的方法体,那我们就空着不久行啦?为什么还要这么麻烦,定义抽象类和抽象方法呢???
引入抽象类,其实是Java提供一种语法工具,作用是引导和规范使用者正确的使用她们,减少误用。
使用抽象类,类使用者在创建对象时,就不会误用不完整的抽象父类实例化进行实例化(编译器会报错),就知道必须使用某个具体的子类来进行实例化。且子类继承是,就要求必须实习其抽象方法,而不可能忽略。
对于类,是具体事物抽象而成。类的概念强调类型。但是在解决问题的大多数情况下,我们并不强求一定需要某个类型。为什么这么说呢?
比如我们现在的需求是:拍照。那我们可以用手机、相机…只要能满足拍照功能的即可,我们不在意是什么类型,而是在意此事物是否有此功能,有就来。
在很多情况下就是如此,类型不重要,重要的是能力。
Java中用一种扩展类-----接口(interface)来显现能力。今天,瑶瑶子带大家系统学习一下Java中的接口。
简单来说,接口就是声明一组能力的类。接口内部声明了很多方法(一般是抽象),也就是功能,但接口本身不去做实现(每个类型的实现方法本就不同,没有必要去实现)。当 实现(implements) 了该接口,就证明这个类,拥有了该接口中声明的方法(即能力)。这样,就达到了表示能力的目的。
接口的定义,和类的定义十分相似:
interface SendMessage {
public static final String MSG = "yaoyao";
public abstract void print();
}
1. 使用interface
关键字来定义一个接口(与类的定义对比:将class换成了interface)
2. 接口的修饰符只能是public
和默认
,这点和普通类是一样的
3. 接口命名,一般以大写字母I
开头
4. 接口命名一般以形容词
词性单词(表示能力嘛~
和类相似,接口内部也可定义属性和方法。但对于属性和方法的声明定义,有一定的语法规则。
可省略
不写,默认就是它们;注意,因为是常量,所以接口中的属性必须显示初始化可省略
接口名.方法名(参数列表)
调用阿里编程规范中,接口的属性和方法不要加任何修饰符(因为上面说了,默认就有的,可以省略
上面提到,接口的本身其实就是声明一些功能,单单有接口,这不是接口设计的初衷.
接口设计的初衷就是将接口也和类一样,作为一个Subtype
(超类),供其他类去实现(拥有功能).
接口不能实例化,必须有一个“实现类”来实现接口,实现接口中的所有抽象方法。
那如何去实现接口呢?
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
表示实现某个接口.前面是子类名,后面是要实现的接口的接口名
一个子类可以实现多个接口,接口名之间用英文逗号,
分隔
普通类实现接口,在该类中必须全部重写实现的接口中定义的抽象方法
一般来说,是普通类实现接口比较常见,但是由于普通类实现接口必须必须重写接口中所有抽象方法,这样在一些情况下会造成代码冗余.
由此,抽象类来实现接口就可以很好的解决这一问题,因为抽象类可以选择性的实现接口中的抽象方法.——实现接口中的部分抽象方法
这样一来,可以让抽象类来实现一部分常用的方法,剩下一部分让子类自己实现,来简化书写.
(ps:但是继承了一个类,就不能继承其他类了,这又是基于Java单继承模式的让普通类继承抽象类的弊端)
一个类的父类和这个类实现的所有接口都称为超类型(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 {
}
♂️接口多态的意义: 让程序员“忘记”类型。类的使用者就不用关注具体类型,而只关注某个类是否具有某种功能!
在上面我讲到,接口可以继承接口,这和类的继承是相似的。有以下需要注意的点:
//一个接口可以继承多个父接口举例:
Interface A{
void method01();
}
Interface B{
void method02();
}
Interface C extends A,B {
}
其实于其叫作接口的继承,不如取extends
本身意思,“扩展”.即接口的扩展。时B接口同时扩展了A接口中的功能。
意义
当我们,只关心实现功能时(需要实现的功能已经确定),具体用什么类型来实现,并不想具体去操心
以下是利用接口和接口多态的一个小案例:模拟数据库的连接
体会接口的好处
数据库接口:
//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();
}
}
这里就官方给出的解释基础上,还添加汇总一些接口使用细节和注意事项
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
的那个父类。你不能说手机是拍照把?
③接口的实现,让相关类不必再共享同一个抽象超类
④ 接口不可被实例化
⑤接口中通常声明一个或多个抽象方法
⑥无关的类们可以通过实现接口中的抽象方法来实现接口
⑦接口不可继承普通类,但接口可继承接口
⑧接口本身就是抽象的,所以可以被abstract
修饰
类的使用者就不用关注具体类型,而只关注某个类是否具有某种功能!
区别 | 抽象类(abstract) | 接口(interface) | |
---|---|---|---|
1 | 结构组成 | 普通类+抽象方法 | 全局常量+抽象方法+默认方法+ 静态方法 |
2 | 子类使用 | 使用extends 关键字,继承抽象类 |
使用implements 关键字实现接口 |
3 | 关系 | 一个抽象类可以实现若干接口 | 接口不能继承抽象类,但是接口可以使用extends 扩展多个接口 |
4 | 子类限制 | 一个子类只能继承一个抽象类 | 一个类可以实现多个接口 |
抽象类和接口配合而非替代的关系。一个类通常有一个抽象类,该抽象类提供默认实现,实现全部或部分方法;可以实现多个接口,表示有多种功能!
Java岛冒险记【从小白到大佬之路】
LeetCode每日一题–进击大厂
Go语言核心编程
算法