Java接口(interface)的概念及使用

    |     2015年4月1日   |   Java面向对象高级特性   |     0 条评论   |    1598

抽象类里可以有抽象方法,也可以有已经实现的方法;接口(interface)更“抽象”:传统上它规定一个类必须做什么,而不规定怎么做。

接口用 interface 声明,可以看成一种特殊的抽象类。Java 8 起接口也可以有 default / static 方法,Java 9 还可以有 private 方法;入门仍应先掌握“常量 + 抽象方法”这一经典形态。

现实里也有接口:Serial ATA 委员会制定 Serial ATA 2.0 规范,自己不生产硬盘。希捷、日立、三星按规范做盘,就可以互换——160G 日立串口盘换成 320G 希捷串口盘,插上就能继续用。

点 接口规则
字段 默认 public static final,必须显式初始化
方法(经典) 默认 public abstract,不能有方法体
构造 / new 没有构造方法,不能直接实例化
继承 接口可继承多个接口;类可实现多个接口

一、声明接口

用代码模拟委员会定义的串口硬盘接口。源文件里可以定义多个类或接口,但最多一个 public,有的话文件名必须和它同名。接口之间也可以继承,子接口拿到父接口的常量和抽象方法,再追加自己的。

public interface SataHdd {
    public static final int CONNECT_LINE = 4;  // 连接线数量
    public void writeData(String data);
    public String readData();
}

成员变量默认就是 public static final,声明时常量修饰符可以省略,但必须显式赋初值。下面这些写法会编译出错:未初始化的字段、protected 方法、带方法体的静态方法(Java 8 以前)。

public interface SataHdd {
    public int connectLine;           // 出错:被看成静态常量,必须初始化
    protected void writeData(String data);  // 出错:必须是 public
    public static String readData() {       // Java 8 前出错:不能有方法体
        return "数据";
    }
}

一个接口不“实现”另一个接口,但可以同时继承多个接口,用来补上类的单继承限制:

public interface SataHdd extends A, B {
    public static final int CONNECT_LINE = 4;
    public void writeData(String data);
    public String readData();
}
interface A { public void a(); }
interface B { public void b(); }

二、为什么使用接口

大型项目里可能要从继承链中间插入能力:A → B → C → D → E。若只想给 C、D、E 加功能,最简单是让 C 再继承另一个类,但 Java 单继承做不到;把新父类挂到 A 上,又会改动整条链,没有可插入性。

接口是可插入性的保证。继承链上任何一个类都可以 implements 一个接口,只影响它自己和子类,不影响父类。我们关心的不是哪一个具体类,而是它有没有实现我们需要的接口。系统越大、活得越久,接口越能保住灵活性和可扩展性。设计阶段最重要的任务之一,就是先画出各部分接口,再组合出框架。

三、用类实现接口

不能 new 接口,必须由类 implements 抽象方法再实例化。一个类实现不了全部抽象方法,就必须把自己声明为抽象类。允许定义接口类型的引用,指向实现类实例。一个类只能继承一个父类,但可以实现多个接口。

格式:修饰符 class 类名 extends 父类 implements 接口1, 接口2 { … }

import static java.lang.System.*;
public class Demo {
    public static void main(String[] args) {
        SataHdd sh1 = new SeagateHdd();
        SataHdd sh2 = new SamsungHdd();
        sh1.writeData("demo");
        sh2.writeData("demo");
    }
}
interface SataHdd {
    public static final int CONNECT_LINE = 4;
    public void writeData(String data);
    public String readData();
}
interface fixHdd {
    String address = "北京市海淀区";
    boolean doFix();
}
class SeagateHdd implements SataHdd, fixHdd {
    public String readData() { return "数据"; }
    public void writeData(String data) { out.println("写入成功"); }
    public boolean doFix() { return true; }
}
class SamsungHdd implements SataHdd {
    public String readData() { return "数据"; }
    public void writeData(String data) { out.println("写入成功"); }
}
abstract class XXHdd implements SataHdd {
    public String readData() { return "数据"; }
    // 没有实现 writeData,所以必须是抽象类
}

四、接口作为类型

任何实现该接口的实例都可以存在接口类型的变量里。通过这个变量调用的是接口里声明的方法,运行时动态绑定到实现类。接口也可以当方法参数和返回类型。

public class Demo {
    public void test1(A a) {
        a.doSth();
    }
    public static void main(String[] args) {
        Demo d = new Demo();
        A a = new B();
        d.test1(a);
    }
}
interface A {
    public int doSth();
}
class B implements A {
    public int doSth() {
        System.out.println("now in B");
        return 123;
    }
}

运行结果:now in B。

一句话总结:接口规定必须做什么;类去 implements,引用写成接口类型,换实现就像换一块符合同一规范的硬盘。

转载请注明来源:Java接口(interface)的概念及使用
本文链接地址:https://ai.zhousir.top/?p=124
回复 取消