接口

作者: 许宏川 | 来源:发表于2015-07-28 22:22 被阅读642次

什么是接口##

抽象类中包含普通方法和抽象方法,如果把抽象类进行更彻底的抽象,即所有的方法都是抽象方法,那就是另外一个机制 —— 接口。
接口和类很相似,但接口不是类,它不像抽象类属于一种特殊的类。在常量、变量与运算符(一) 这篇文章里对引用数据类型分类过,接口属于引用数据类型的一种,它和类是同等级的概念而不是包含关系。

接口听起来很像是电脑主板上的USB接口或者PCI接口,或者插座上的插孔。很多教材也会这么比喻,其实这是错误的理解。如果要以主板上的接口比喻,例如USB接口,那么接口应该USB接口应该遵守的规范而不是接口本身。所以接口这个名字很容易让新人误解。

接口是干什么的##

要说接口是干什么的,我认为有两个关键字,一是规范,二是能力。接口通常用来规定实现这个接口的类必须遵守的规范,或者类必需具备的能力。

语法##

接口既然不是类,那么定义接口是自然不再是用class这个关键字了,而是用<code>interface</code>关键字。
接口和抽象类一样不能实例化,也不能被类继承,它的使用方法是让类实现它。关键字是<code>implements</code>。
接口可以继承其它接口,而且可以多继承。

定义接口的语法是:

[访问修饰符] interface 接口名 extends 父接口1, 父接口2, 父接口3... {
        [public static final]属性;
        [public]static方法;
        [public]default方法;
        [public abstract]方法;
        [public static]内部类;
        [public static]内部接口;
        [public static]内部枚举;
}

使用接口的语法是:

class ClassName implements 接口1, 接口2, 接口3... {

}

从定义接口的语法可以看到接口内部成员可以是static 属性、static 方法、default 方法、抽象方法、内部类、内部接口、内部枚举。后面三个内部类、内部接口和枚举现在我没写到先不谈。说说前面四个。

  • static 属性
    关于接口的static 属性有以下四点要说明的地方:

    • 接口所有的属性都是用public static final修饰。所以你写不写修饰符默认都是public static final。也就是说在接口里写<code>public static final String s</code>和<code>String s</code>是等效的。
    • 因为接口不能实例化,也不能有static代码块。而属性都是final的,所以必须指定初始值。
    • 可以用接口调用static属性,接口不能实例化就是没有接口的对象,但是可以用实现了这个接口的类的对象调用static属性,但是建议用接口来调不要用对象来调,这样比较规范,这样一看就知道是属于接口的方法。
    • 如果接口A、接口B都有属性s。类C实现了A和B接口,那么就不能用类C的对象来调用s属性,因为不知道到底调用A.s还是B.s。
  • static 方法
    关于接口的static 方法有以下两点要说明的地方:

    • 所有static 方法都是用public修饰,写不写public都一样。
    • static 属性可以用实现了这个接口的类的对象来调用,但是static 方法不能,只能用接口来调用。
  • default 方法
    关于接口的default 方法有以下三点要说明的地方:

    • 所有default方法都是用public修饰,写不写public都一样。
    • 跟普通方法一样,使用实现了这个接口的类的对象调用default 方法。
    • 如果接口A、接口B都有default 方法m()。类C实现了A和B接口,那么类C就必须重写m(),否则m()方法冲突不知道实现的是A.m()还是B.m()。如果希望实现的是A.m()可以在重写m()的时候使用A.super().m()来复用代码。

我举个例子来使用以下接口的 static 属性、static 方法和default 方法。
示例代码:
创建接口A,在前面加大写字母I是规范,方便和类区分。
接口A有static 属性,static 方法和default 方法。

public interface IA {

    String s = "我是接口A的static 属性";

    static void show() {
        System.out.println("我是接口A的static 方法");
    }

    default void defaultMethod() {
        System.out.println("我是接口A的default 方法");
    }

}

创建接口B,接口B有一个和接口A里同名的default 方法。

public interface IB {

    default void defaultMethod() {
        System.out.println("我是接口B的default 方法");
    }

}

创建类C实现接口A和接口B,用逗号隔开。因为接口A和接口B中都有名为defaultMethod()的default 方法,所以类C里必须重写。

public class C implements IA, IB {

    @Override
    public void defaultMethod() {
        //因为IA, IB都有defaultMethod(),所以冲突了,必须重写
        IB.super.defaultMethod(); // 通过接口名.super.xx() 来调用接口的default 方法
    }
}

测试代码:

C c = new C();
System.out.println(IA.s); //static 属性可以通过对象c来调但是不建议这么做,避免混淆
IA.show(); //static 方法只能通过接口调
c.defaultMethod(); // default 方法通过对象c来调

运行结果:

<pre>
我是接口A的static 属性
我是接口A的static 方法
我是接口B的default 方法
</pre>

以上是关于接口的static 属性,static 方法和default 方法。但是这三个成员其实不是很常用,最常用的是抽象方法。这个作为重点来讲:

  • 抽象方法
    关于接口的abstract方法有以下三点要说明的地方:
    • 抽象类可以有普通方法和抽象方法,但是接口只能有抽象方法
    • 接口的抽象方法和抽象类里的抽象方法一样,只是默认都是用<code>public abstract</code>修饰
    • 类C实现接口A,那么类C必须实现接口A的所有抽象方法,除非类C是抽象类

来看示例代码,来个复杂点的例子。继续抽象类与抽象方法 里的示例代码。
创建一个ITransport接口,有一个传输文件抽象方法。前面说接口通常用来定义规范和能力,这个传输文件就可以视为一种能力。实现这个接口的类必须有传输文件的能力。

public interface ITransport {
    
    //在两个硬盘间传输文件
    void transport(Dish dish1, Dish dish2);

}

创建一个ISATA和IUSB接口都继承ITransport,各自添加一个connection方法。以ISATA为例,它继承了ITransport那么也就继承了transport这个方法。即是说实现ISATA必须实现transport和connection两个方法。

public interface ISATA extends ITransport {

    // 连接硬盘到主板
    void connection(HDD hdd);

}
public interface IUSB extends ITransport {

    // 连接U盘到主板
    void connection(UDish uDish);

}

创建一个主板类实现ISATA和IUSB两个接口,按照接口规定的能力它必须实现void transport(Dish dish1, Dish dish2);、void connection(HDD hdd);、void connection(UDish uDish);三个方法。

public class MotherBoard implements ISATA, IUSB {

    @Override
    public void transport(Dish dish1, Dish dish2) {
        connection(dish1);
        connection(dish2);
        if (dish1.getIsConnection() && dish2.getIsConnection()) {
            int speed1 = dish1.getSpeed();
            int speed2 = dish2.getSpeed();
            int speed = (speed1 > speed2 ? speed2 : speed1); // 传输速度取决于速度慢的那个
            System.out.println("以" + speed + "MB/S的速度传输文件");
        }
    }

    //连接硬盘,返回是否连接成功
    boolean connection(Dish dish) {
        if (dish instanceof HDD) {
            connection((HDD)dish);
            return true;
        } else if (dish instanceof UDish) {
            connection((UDish)dish);
            return true;
        } else {
            System.out.println("连接失败,主板与" + dish.getName() + "不兼容");
            return false;
        }
    }

    @Override
    public void connection(HDD hdd) {
        hdd.setIsConnection(true);
    }

    @Override
    public void connection(UDish uDish) {
        uDish.setIsConnection(true);
    }

}

定义一个硬盘根类,抽象类无法实例化。有name、iSConnection两个属性和对应的getter()和setter(),有一个获取传输速度的getSpeed();方法交给子类去实现。

public abstract class Dish {

    protected String name;
    protected boolean iSConnection; // 是否连接到主板

    public String getName() {
        return this.name;
    }

    public boolean getIsConnection() {
        return this.iSConnection;
    }

    public void setIsConnection(boolean isConnection) {
        this.iSConnection = isConnection;
    }

    public abstract int getSpeed(); // 传输速度

}

创建HDD、USB和TypeC三个类都继承自Dish,只是名字和传输速度不同。

public class HDD extends Dish {

    public HDD() {
        this.name = "HDD";
    }

    @Override
    public int getSpeed() {
        return 500;
    }

}
public class UDish extends Dish {

    public UDish() {
        this.name = "UDish";
    }

    @Override
    public int getSpeed() {
        return 150;
    }

}
public class TypeC extends Dish {

    public TypeC() {
        this.name = "TypeC";
    }

    @Override
    public int getSpeed() {
        return 1000;
    }
}

测试代码:

    HDD hdd = new HDD();
    UDish uDish = new UDish();
    TypeC tc = new TypeC();
    MotherBoard mb = new MotherBoard();
    
    mb.transport(hdd, uDish);
    mb.transport(hdd, tc);

运行结果:

<pre>
以150MB/S的速度传输文件
连接失败,主板与TypeC不兼容
</pre>

本文代码下载:百度网盘

相关文章

  • 接口接口接口

    发现很多朋友对于接口都很纠结,阐述一下个人对接口的理解。 接口分为很多种类型,程序语言内部接口 移动端和服务端接口...

  • Android常用接口

    不知名接口 头条接口: 科技接口: 财经接口: 军事接口: 体育接口: 房产接口: 足球接口: 娱乐接口: 电影接...

  • 第十八天 微信微博天气接口

    分享接口 微信接口 微博接口 天气接口 mob接口

  • 接口测试概述

    接口(interface)的概念 常见接口名词 接口测试: 接口测试目的: 接口测试的重要性: 接口测试流程 接口...

  • 接口测试

    接口测试概念: 接口:接口是为了提供一种服务 所有的接口统称为API,接口分为内部接口和外部接口 外部接口:测试被...

  • 接口

    接口 接口类型 空接口 接口嵌套 接口断言 type关键字

  • 线程池原理

    Callable 接口 Runnable 接口 Future接口 RunnableFuture 接口 Future...

  • JMeter-一个接口的返回值作为输入传给其他接口

    背景: 在用JMeter写接口case,遇到一种情况,接口1查看列表接口,接口2查看详情接口,接口2需要传入接口1...

  • 用户操作接口

    登陆 接口地址 获取列表 接口地址 删除 接口地址 批量删除 接口地址 编辑用户 接口地址 添加用户 接口地址

  • JAVA中的集合框架 List (二)

    Collection接口List接口简介 Collection接口、子接口及其实现类,Collection接口是j...

网友评论

      本文标题:接口

      本文链接:https://www.haomeiwen.com/subject/tmcmqttx.html