接口

一.抽象方法及抽象类

1-1 抽象方法

抽象方法:这种方法是不完整的,仅有声明而没有方法体。

public abstract void f();

1-2 抽象类

  • 包含抽象方法的类一定是抽象方法,该类必须使用abstract关键字将其限定为抽象的,否则编译器会报错;
  • 抽象类可以不包含抽象方法;
  • 如果从一个抽象类继承,并想创建该导出类的对象,那么就必须为基类中的 所有抽象方法提供方法定义(方法体)。如果不这样做(可以选择不这样做),那么导出类依然是抽象类,且编译器会强制我们用abstract关键字来限定这个导出类;
  • 不能为抽象类创建对象。

虽然不能为抽象类创建对象,但是抽象类中的非抽象方法仍然可以通过抽象类的引用去调用,以下为一种情形:

package com.hutao.page.page170;
import static com.hutao.util.Print.*;

abstract class Instrument{
    private int i;
    public abstract void play(Note n);
    public String what(){
        return "Instrument";
    }
    public abstract void adjust();

}

class Wind extends Instrument{
    public void play(Note n){
        print("Wind.play()"+n);
    }
    public void adjust(){}
}

public class Music4 {
    public static void main(String[] args) {
        Instrument instrument = new Wind();
        print(instrument.what());
    }
}

运行结果为:

Instrument

Process finished with exit code 0

这里能通过抽象类引用instrument调用其非抽象方法what()是因为导出类Wind没有覆盖抽象类Instrument的what()方法,所以通过基类引用调用what()方法时,根据总是调用最派生方法的原理(Most derived,在https://www.cnblogs.com/certainTao/p/14798451.html的1-3中有介绍),调用的就是基类的what()方法。

二.接口

interface关键字产生一个完全抽象的类,它不提供任何具体的实现。

接口可以包含域,但这些域是 隐式static和final的。

  • 是static的原因可能是:接口不能被实例化,域只能与类相关,所以为static;
  • 是final的原因可能是:interface设计的初衷就是将其作为规范的,不可更改,所以域也是不可以被修改的。

接口中的方法声明默认是public和abstract的,这意味着可以不显示的指明public abstract修饰。

public abstract void print(); = void print();

注意:在实现接口中的方法时,实现类中实现方法的修饰符应保持 >=接口中对应的方法声明的修饰符。因为接口中的方法声明默认是public的,那么实现类中实现方法的修饰符也应是public的(public>protected>包访问权限>private)。

2-1 通过继承扩展接口

可通过继承在新接口中组合多个接口。extends可用于多个接口基类(接口可以多继承)。

一个接口的实现类对象可以向上转型为该接口的类型及其所有祖先接口(有继承关系)类型。

package com.hutao.page.page180;

interface Monster{
    void menace();
}

interface DangerousMonster extends Monster{
    void destroy();
}

class DragonZilla implements DangerousMonster{
    public void menace(){}
    public void destroy(){}
}

interface Lethal{
    void kill();
}

//接口可通过继承(支持多继承)来扩展接口
interface Vampire extends DangerousMonster, Lethal{
    void drinkBlood();
}

class VeryBadVampire implements Vampire{
    public void menace(){}
    public void destroy(){}
    public void kill(){}
    public void drinkBlood(){}
}

public class HorrorShow {
    static void m(Monster m){
        m.menace();
    }
    static void d(DangerousMonster d){
        d.menace();
        d.destroy();
    }
    static void l(Lethal l){
        l.kill();
    }
    static void v(Vampire v){
        v.menace();
        v.destroy();
        v.kill();
        v.drinkBlood();
    }

    public static void main(String[] args) {
        DangerousMonster dangerousMonster = new DragonZilla();
        m(dangerousMonster);
        d(dangerousMonster);

        Vampire vampire = new VeryBadVampire();
        m(vampire);
        d(vampire);
        l(vampire);
        v(vampire);
    }
}

上述接口和类之间的关系为:

接口

所以DangerousMonster接口的实现类对象new DragonZilla()可向上转型为DangerousMonster,Monster类型;Vampire接口的实现类对象new VeryVadVampire()可向上转型为Vampire,DangerousMonster,Lethal,Monster类型。

2-2 组合接口时的名字冲突

前提:一个类或者接口中不允许出现两个签名(方法名和形参列表)一致的方法,不论这两个方法的返回值类型是否一致。

class SameErasure {
    void method() { }

    int method() { return 1; }
}

接口

现在有这样一组接口和类:

interface I1{
    void f();
}

interface I2{
    int f();
}

class C{
    public void f(){
        System.out.println("C.f()");
    }
}

①一个新的接口AssemblyInterface组合接口I1和I2:

interface AssemblyInterface extends I1, I2{

}

接口

分析:因为接口I1和I2中的两个方法的签名相同,而接口AssemblyInterface组合了这两个接口,就相当于AssemblyInterface接口中有了两个签名一样的方法,不被允许。

②一个类AssemblyClass1继承了类C并实现I1接口:

class AssemblyClass1 extends C implements I1{

}

public class Test{
    public static void main(String[] args) {
        AssemblyClass1 assemblyClass1 = new AssemblyClass1();
        assemblyClass1.f();
    }
}

运行结果为:

C.f()

Process finished with exit code 0

这里有个现象:AssemblyClass1类 implements了I1接口 ,看起来并未在类中实现I1接口中的void f()方法,但却能创建此类的对象,并成功调用void f()方法(编译通过)。

分析:C类中有一个有方法体的public方法void f(),所以子类AssemblyClass1类中也就有一个pulic void f()方法(有方法体);I1接口中有一个void f()声明,所以实现类AssemblyClass1中就有一个void f()方法需要实现。而此时,AssemblyClass1类中已经一个有方法体的void f()方法了,相当于继承自父类的方法实现了接口中需要实现的方法。

③一个类AssemblyClass2继承了类C并实现了I2接口:

class AssemblyClass2 extends C implements I2{

}

分析:AssemblyClass2类中有一个继承而来的public void f()方法,因为AssemblyClass2实现了I2接口,所以就需要在类中去实现方法public int f(),这就会出现一个类中有两个签名一样的方法的情况。

Original: https://www.cnblogs.com/certainTao/p/14825528.html
Author: certainTao
Title: 接口

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/585277/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • linux mv 命令中断的解决办法

    背景:使用mv对服务器文件进行迁移的过程中,因为网络中断,所以迁移到一半被停止了。 现状:有一部分文件没有迁移完,但是文件夹已经存在了,重新mv提示文件夹已经存在,切已经有文件,所…

    Linux 2023年5月27日
    0102
  • [ Linux ] column 简明用法

    options -c 指定每一行输出的宽度。 -t 判断列来输出,对齐所有列。 主要用到的就是这个选项。 -s 指定分隔符,默认为空白符。 -o 指定用于对齐列填充的符号,默认为空…

    Linux 2023年6月7日
    092
  • OpenWRT TP_LINK703N 校园网 锐捷认证解决办法

    OpenWRT TP_LINK703N 校园网 锐捷认证解决办法 一、准备的工具 1) SSH登录工具,推荐使用MobaXterm_Personal下载链接https://moba…

    Linux 2023年6月6日
    083
  • 性能压测时 数据库服务器CPU使用率过高的解决方案

    1、确定是否有慢sql语句; 1)登录数据库服务器,连接数据库;执行命令:mysql -uroot -p 密码 2)查看慢sql日志是否开启,执行命令:show variables…

    Linux 2023年6月8日
    083
  • gitlab

    版本控制gitlab 1. 版本控制介绍 2. gitlab部署 版本控制介绍 版本控制是指对软件开发过程中各种程序代码、配置文件及说明文档等文件变更的管理,是软件配置管理的核心思…

    Linux 2023年6月7日
    0113
  • Linux目录结构

    一、基本介绍 linux文件系统采用级层的树状目录结构,最上层的就是根目录 / ,在此基础上创建其他目录。在linux中一切皆为文件 二、详细目录介绍 /bin(不可随意更改):该…

    Linux 2023年6月6日
    0124
  • 本篇还玩“障眼法”,一文解读HTML内联框架Iframes。

    写在开篇 假设有一个需求,想要在网页内显示其它网页,怎么搞?很简单,可以用iframe来解决,那啥是iframe?本篇的主题就是它,接下来我们一一解剖它的用法。 嵌入第三方url页…

    Linux 2023年6月7日
    0102
  • JCL 日志门面

    JCL( Jakarta Commons Logging ),是 Apache 提供的一个 通用日志 API 。用户可以自由选择第三方的日志组件作为具体实现,像 Log4j 或 J…

    Linux 2023年6月8日
    073
  • OpenStack 创建自定义的QCOW2格式镜像

    一、安装KVM虚拟机 1.1 虚拟机安装虚拟化软件包 注意:虚拟机指的是CentOS7.8 #挂载光盘 [root@cloudcs ~]# mount /dev/cdrom /mn…

    Linux 2023年6月8日
    074
  • 线程池如何保证核心线程一直存活

    转载请注明出处: 查看 ThreadPoolExecutor 类中的 getTask 方法,这个方法可以保持核心线程在没有任务的时候也可以一直处于存活状态 核心在于 workQue…

    Linux 2023年6月14日
    0151
  • bash脚本-周末定时备份mysql数据库

    1.脚本如下 #usr/bin/sh #program:用于每周日定时备份全天候mysql文件 #author:sundz #version:v1 20220521 #定义文件夹和…

    Linux 2023年6月7日
    095
  • Ubuntu无法telnet

    (1)/etc/hosts被修改过 (2)防火墙没有关闭 (3)没有安装相关服务 (4)/etc/inetd.conf文件没有telnet相关内容 (1)把/etc/hosts文件…

    Linux 2023年6月8日
    088
  • 什么是可调CAP策略?为什么需要可调CAP策略?

    在说可调CAP策略之前,我们要先说说CAP理论。 CAP理论是设计分布式系统必用的黄金法则,它提出了设计分布式系统的三个基本要求:一致性(Consistency)、可用性(Avai…

    Linux 2023年6月6日
    0104
  • 使用SpringBoot校验客户端传来的数据

    前端的数据校验都是辣鸡!后端天下第一! 如果想完美地贯彻原则, 理论上来说就应该让前端那边少传数据过来, 有些的东西能查的就自己查出来。 常用的数据校验like this: /**…

    Linux 2023年6月14日
    066
  • debian与windows时间不同步的简单治疗方法

    试过几种方法, 但就这个方法好使点。hwclock -w –localtime Original: https://www.cnblogs.com/leotiger/p…

    Linux 2023年6月13日
    067
  • 订阅消息组件由 redis 改为 rabbitmq

    刚开始测试 dapr 时为了图省事,使用了 pubsub.redis,现在准备上生产环境,改用支持消息持久化的 pubsub.rabbitmq。 之前使用的 pubsub.redi…

    Linux 2023年5月28日
    073
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球