• Java 抽象类与接口


    一、抽象类

    1.1 抽象类的声明

    可以这样认为,抽象类就是普通类抽象化的结果,它与普通类相比,同样具有属性、方法等,唯一的区别就是抽象类具有抽象的效果,即无法被实例化(如果可以被实例化,就失去抽象的意义了)。抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

    由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。而一些具体类(相对于抽象类而言的普通类)的父类一般就是抽象类或者其他基类。

    这里要说明的一点就是,抽象类 ≠ 基类。基类一般而言都是非抽象类,从名字上可以知道,基类意为基本的类,应该是多个子类的同时继承的一个父类,此父类拥有这些子类所共用的属性和方法,也就是说,基类是这些子类的基本。而抽象类是具体类的抽象,两者完全不一样。此外,基类只是开发人员对多个子类的共同父类的一种说法而已,Java 中并没有专门的基类对象,但是抽象类是有的。

    抽象类通过在 class 关键字前面添加 abstract 关键字来声明:

    abstract class AbstractClassExample {}

    抽象类无法被实例化,因此,当你执行以下语句时,将会触发报错:

    1. abstract class AbstractClassExample {}
    2. public class Test {
    3. public static void main(String[] args) {
    4. AbstractClassExample abstractClassExample = new AbstractClassExample();
    5. // Error: AbstractClassExample 是抽象的; 无法实例化
    6. }
    7. }

    因此,我们应该通过继承抽象类来使用抽象类。抽象类的继承和普通类无异。

    1.2 抽象方法

    与抽象类相似,方法也可以被抽象化,这样的方法被称为抽象方法,其与普通方法的差异和抽象方法与普通方法的差异类似,但略有一些不同。抽象方法既然是抽象的,那就没有具体的实现过程,因此也就没有方法体了(就算有,也只能是空的,还不如没有,因此不允许有方法体)。

    抽象方法的声明如下:

    1. abstract class AbstractClassExample {
    2. abstract void abstractMethod(); // 此处的返回类型没有强制为 void,这里只是举例
    3. }

    这里要注意的几点是:

    • 如果一个类包含抽象方法,那么该类必须是抽象类,但抽象类并不是一定要包含抽象方法;
    • 抽象类被具体类继承后,其中的抽象方法必须被重写;
    • static 关键字修饰的方法不能为抽象方法,因为含义上有冲突,使用方式也有冲突;

    如果具体类不重写抽象方法,将会触发报错:

    1. abstract class AbstractClassExample {
    2. abstract void abstractMethod();
    3. }
    4. class ConcreteChildClass extends AbstractClassExample {}
    5. // Error: ConcreteChildClass不是抽象的, 并且未覆盖AbstractClassExample中的抽象方法abstractMethod()

    那么,有一个问题,既然抽象类无法被实例化,那它能不能有构造方法呢?按道理说,不能被实例化,构造方法就没有用啊,存在的意义是什么呢?

    但其实,在 Java 中,抽象类是可以有构造方法的。尽管抽象类无法被实例化,看似抽象类没有任何作用,但其实它可以被具体类继承,从而调用相关的方法。抽象类本就是具体类的抽象化,其本身具有抽象意义,但并不代表它不能拥有构造方法。

    二、接口

    接口在 Java 编程语言中是一个抽象类型,是抽象方法的集合,接口通常以 interface 关键字来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

    接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法(要实现,但并没有真的实现,只是描述有没有这样一个方法)。

    除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。

    接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

    2.1 接口的声明

    接口通过 interface 关键字来声明,interface 翻译过来就是接口的意思。

    interface InterfaceExample {}

    注意,接口是隐式抽象的,不需要显示对其使用 abstract 关键字进行修饰,其方法也是隐式抽象的,不必添加 abstract 关键字,当然,加了也不会报错,但是没必要。接口的方法也都是隐式公有的,因此也无需对其方法添加 public 关键字,加了不会报错,但是没必要。

    注意,接口的方法隐式抽象并非指其只能为抽象的,也可以是非抽象的方法,如通过 static 关键字进行修饰后的方法就不是抽象方法。

    接口是隐式抽象的,无法被实现,因此下面的代码将会报错:

    1. abstract interface InterfaceExample {}
    2. public class Test {
    3. public static void main(String[] args) {
    4. InterfaceExample interfaceExample = new InterfaceExample();
    5. // Error: InterfaceExample 是抽象的; 无法实例化
    6. }
    7. }

    注意上面的报错信息,并没有说接口是抽象类,只是说它是抽象的,无法被实现。接口不是类,尽管两者在很多地方非常相似。

    2.2 接口的实现

    接口的实现有点类似于抽象类的实现,不过“继承”接口的方式不一样,不是通过 extends 关键字,而是通过 implements 关键字。implements 翻译过来就是实现的意思。

    实现其的必须是类,如果这个类是抽象类,那么其不必将接口中的方法全部实现,如果是具体类,则需要将接口中全部的方法都实现,因为这些方法是隐式抽象的。

    接口的实现,为什么要用 implements 关键字来声明,而不是继续用 extends 关键字呢?难道仅仅只是因为含义不同吗?这其实并不是 Java 当初故意设计的,而是因为 extends 关键字对于接口而已另有它用。实际上,类与接口之间的关系是下面这样的:

    类与接口的关系

    上图中,抽象类被包含在类里面了。“实现”(implements)一定会真正地实现方法的功能,即有方法体,且方法体中有具体的内容,而继承只是将其父类(父接口)的属性和方法“拿”过来用。简单说,“继承”就是“是不是”的问题,而“实现”就是“有没有”的问题。

    可以这样简单的理解,接口之间的继承就类似于抽象类之间的继承,因为抽象类和接口真的非常相似,但必须明确,它们不是同一个东西,接口甚至都不是类。

    此外,要注意,继承时只能继承一个类或者接口,但是实现可以一次多个接口。

  • 相关阅读:
    [Google DeepMind] LARGE LANGUAGE MODELS AS OPTIMIZERS
    Java数学工具类Math的Math.round()方法
    【Try to Hack】Windows系统账户安全
    后端程序员入门react笔记(五)ajax请求
    1024程序员节来了,
    python 对图像进行聚类分析
    【Linux】系统中安装Go环境
    40.Java之Class、Type详谈
    深圳xxx公司测试岗位企业面试题
    C# Winform编程(1)基础篇
  • 原文地址:https://blog.csdn.net/weixin_62651706/article/details/133841334