接口

一.抽象方法及抽象类

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)

大家都在看

  • ajax跨域问题

    public class CrosFilter implements Filter { @Override public void destroy() { // TODO Auto…

    Linux 2023年6月7日
    0104
  • .NET Core 3.0, 发布将于今晚开始!

    期待已久的.NET Core 3.0即将发布! .NET Core 3.0在.NET Conf上发布。大约还有9个多小时后,.NET Conf开始启动。 第1天-9月23日 9:0…

    Linux 2023年6月7日
    086
  • 保姆教程系列一、Linux搭建Nacos

    前言: 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i 简介: Nacos是阿里巴巴开源的一款支持服务注册与发现,配置管理以及微服务管理的组件。用来取代以前常用的注册中心…

    Linux 2023年6月14日
    095
  • MySQL优化

    1.建立索引 (1)合理的索引能够加速数据读取效率,不合理的索引反而会拖慢响应速度; (2)索引越多,更新数据的速度越慢 (3)尽量在MyIsam作为引擎的时候使用索引 (4)可在…

    Linux 2023年6月7日
    061
  • 关于如何在window下执行SQLSERVER的定时备份

    引言 在使用SqlServer Express 版本的时候发现,这个版本不支持通过数据库的代理方式进行数据库的维护。 解决方案 使用SQL语句加windows任务计划的方式解决具体…

    Linux 2023年6月14日
    093
  • CMU15-445 数据库导论 Storage01

    CMU15-445 01 Storage 1. 参考资料: [1] CMU15-445:Database Systems [Andy Pavlo] https://15445.co…

    Linux 2023年6月6日
    099
  • redis编译安装

    redis是一个强大的NoSQL数据库,相对于memcached,他提供了更丰富的数据类型,有string、hash、list、set、sorted set这几种类型;还支持数据持…

    Linux 2023年5月28日
    0103
  • Linux修改dns域名配置

    bash;gutter:true;</p> <h1>!/bin/bash</h1> <h1>1.定义DNS的文件</h1&gt…

    Linux 2023年6月13日
    0108
  • Jenkinsfile Pipeline 使用 SSH 连接

    为了在 Jenkinsfile 的命令中使用 SSH,我们不得不通过一些设置… 前提 首先你需要将用到的 SSH 私钥保存到 Jenkins 的凭据中,这样你会获得一个…

    Linux 2023年6月7日
    0116
  • 微信公众号开发之获取微信用户的openID

    (注:openID同一用户同一应用唯一,UnionID同一用户不同应用唯一。不同应用指微信开放平台下的不同用户。) 1、 申请测试号(获得appID、appsecret) 2、 填…

    Linux 2023年6月13日
    080
  • flask 之 请求钩子

    请求钩子 什么是请求钩子? 在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要统一处理,为了让每个视图函数避免编写重复功能的代码, flask提供了统一的接口可以添加这些处理…

    Linux 2023年6月8日
    0107
  • 正则表达式在grep中的使用

    GREP用法 grep "after" profile #查找文件内的包含after单词的行 grep -n "after" profile…

    Linux 2023年6月11日
    098
  • debugfs使用指南

    debugfs 概述 类似sysfs、procfs,debugfs 也是一种内存文件系统。不过不同于sysfs一个kobject对应一个文件,procfs和进程相关的特性,debu…

    Linux 2023年6月7日
    095
  • Shading-JDBC、ShadingSphere、ShardingProxy 使用详解

    ShadingSphere ​ShardingSphere是一款起源于当当网内部的应用框架,2015年在当当网内部诞生,2016年由主要开发人员张亮带入京东数科,在国内经历了当当网…

    Linux 2023年6月6日
    0144
  • shell echo单行和多行文字定向写入到文件中

    单行文本: #!/bin/bash echo "192.168.85.24 tsedb">> /etc/hosts 多行文本: < #!/bi…

    Linux 2023年5月28日
    084
  • Linux系统Yum中的$releasever和$basearch变量

    Yum的配置文件中包含大量的$releasever和$basearch变量,那么他们的取值是什么呢? 为什么要折腾这个玩意呢?有点地方的网络是私有化网络,内部有大量的Linux服务…

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