Java 接口

接口是面向对象的重要概念,在这篇教程会介绍 Java 接口相关内容,并看到 Java 如何使用接口来实现多态多继承

什么是接口

Java 中的接口也是表达了 IS-A 关系,但是接口更多的是一种行为抽象,它是对某一类的多种行为的抽象。所有实现了某个接口的类,都需要实现接口规范的行为。

如果用生活中的事物来举例的话,如果要为人定义一个接口,它通常需要规定如下的行为。

人类:每个人都要吃饭,睡觉。

根据这个人类接口的定义,我们知道人类必须包含吃饭和睡觉行为。不管你是南方人、北方人、外国人,都需要人类这个接口中所规定的吃饭和睡觉行为。虽然可能具体的行为内容不同,但是这两个行为是必须的。

为什么需要接口

可以从以下几点来考虑:

  1. 接口可以对行为进行完全的抽象,规范类的行为,是一种行为契约
  2. 松耦合,提高代码的可读性,接口定义了一组标准的方法,使代码更易于理解和维护,但是不建议多层接口,这会增加代码的复杂性。
  3. 可以实现多态:接口是实现多态性的一种方式,允许不同的对象采用相同的接口进行交互,从而提高代码的可扩展性和可维护性。
  4. 使用接口可以实现 Java 的多继承(Java 类的继承只能单继承)。
  5. 提高交互的安全性:接口可以强制类必须实现某些行为或规则,保证类行为的一致性

Java 接口定义和特点

Java 接口定义通常仅包含被 public 修饰的仅有方法定义的抽象方法,以及被 public static fianl 修饰的常量,同时使用 interface 关键词来代替 class接口不能被实例化。接口定义的常见方式如下:

[权限] interface  interfaceName [ extends  superInterfaceName ] { 
   // 常量
   static final ...;
   // 公共抽象方法的签名
   ...
}

具体例子:

public interface MyInterface {
  String param = null;
  void method1();
}

不过从 Java 8 开始,接口可以有默认方法和静态方法了,从 Java 9 开始,可以添加静态私有方法。

所以现在接口定义也可以像下面这样复杂,不过这是不建议的方式。这会增加代码的复杂性

interface MyInterface {
    String param = null; // 默认被 public static final 修饰
    void method1(); // 默认被 public abstract 修饰
    void method2(); // 默认被 public abstract 修饰
    // 默认方法
    default void defaultMethod() {
        System.out.println("default method");
    }
	  // 私有方法
    private void privateMethod() {
        System.out.println("private method");
    }
  	// 静态方法
    static void staticMethod() {
        System.out.println("static method");
    }
    // 私有静态方法
    private static void privateStaticMethod() {
        System.out.println("private static method");
    }
}

思考:为什么要在接口中增加默认方法、私有方法、静态方法、私有静态方法。

接口特点

Java 中接口的特点如下:

  1. 通常接口中只包含抽象方法的定义(Java 8 可以有默认方法和静态方法,Java 9 可以有私有静态方法)。

  2. 接口的实现类必须实现接口中所有的抽象方法。

  3. 接口的抽象方法默认都是被 public abstract 修饰,子类必须实现。

  4. 接口的属性都是被 public static final 修饰。

    public class JavaInterface3 {
        public static void main(String[] args) {
            System.out.println(MyInterface.param); // 输出:https://www.wdbyte.com
        }
        interface MyInterface{
            String param = "https://www.wdbyte.com";
        }
    }
    
  5. 接口不能被实例化。

  6. 接口可以被多个实现类实现,从而实现多态性。

    interface IMobilePhone{
        void mehtod1();
    }
    class IPhone14 implements IMobilePhone{
        @Override
        public void mehtod1() {
        }
    
    }
    class Xiaomi14 implements IMobilePhone{
        @Override
        public void mehtod1() {
        }
    
    }
    
  7. 接口可以被其他接口继承,从而实现接口的扩展性。

    interface MyInterface1{
        void mehtod1();
    }
    interface MyInterface2 extends MyInterface1{
        void mehtod2();
    }
    
  8. 接口可以用于解耦合,提高代码的可读性和可维护性。

总体来说,Java 接口是一种非常重要的语言特性,可以用于实现多态性、解耦合、提高代码可读性等。

Java 接口实现

接口既然是行为的抽象,那么就需要有具体的行为实现,类对接口的实现就是具体的行为实现。以手机为例。

定义一个手机接口,定义手机系统基本的行为。

/**
 * 手机系统功能接口
 */
public interface IMobilePhoneSystem{
    // 开机
    void powerUp();
    // 显示
    void display();
    // 声音
    void sound();
}

单接口实现

使用 implements 关键词实现接口功能。

public class XPhone implements IMobilePhoneSystem{

    @Override
    public void powerUp() {
        System.out.println("XPhone 开始开机");
    }
    @Override
    public void display() {
        System.out.println("XPhone 开始显示");
    }
    @Override
    public void sound() {
        System.out.println("XPhone 发出声音");
    }
}

多态实现

// IMobilePhoneSystem xPhone = new XPhone();
public class XPhone implements IMobilePhoneSystem{
    @Override
    public void powerUp() {
        System.out.println("XPhone 开始开机");
    }
    @Override
    public void display() {
        System.out.println("XPhone 开始显示");
    }
    @Override
    public void sound() {
        System.out.println("XPhone 发出声音");
    }
}
// IMobilePhoneSystem miPhone = new MiPhone();
public class MiPhone implements IMobilePhoneSystem{

    @Override
    public void powerUp() {
        System.out.println("MiPhone 开始开机");
    }
    @Override
    public void display() {
        System.out.println("MiPhone 开始显示");
    }
    @Override
    public void sound() {
        System.out.println("MiPhone 发出声音");
    }
}

多接口实现

在 Java 中,一个类可以实现多个接口,以上面的例子为例,手机的功能过于原始,我们需要增加新的接口。

/**
 * 手机基本功能
 */
public interface IMobilePhoneBasicFunction {
    // 打电话
    void call();
    // 发短信
    void sendMessage();
}

修改 XPhone 实现多个接口,XPhone 必须实现两个接口中的所有抽象方法。

public class XPhone implements IMobilePhoneSystem,IMobilePhoneBasicFunction{
    @Override
    public void powerUp() {
        System.out.println("XPhone 开始开机");
    }
    @Override
    public void display() {
        System.out.println("XPhone 开始显示");
    }
    @Override
    public void sound() {
        System.out.println("XPhone 发出声音");
    }
    @Override
    public void call() {
        System.out.println("XPhone 开始拨打电话");
    }
    @Override
    public void sendMessage() {
        System.out.println("XPhone 开始发送短信");
    }
}

此时,XPhone 的继承关系如下。

可以对 XPhone 进行测试:

XPhone xPhone = new XPhone();
xPhone.powerUp(); // XPhone 开始开机
xPhone.call(); // XPhone 开始拨打电话

接口继承接口

再次分析上面的两个接口,可以发现,IMobilePhoneBasicFunction 接口和 IMobilePhoneSystem 不应该是相等的关系,IMobilePhoneSystem 应该作为手机功能的基础。因此 IMobilePhoneBasicFunction 需要继承 IMobilePhoneSystem 的所有行为抽象。

接口继承接口

代码实现:

/**
 * 手机基本功能
 */
public interface IMobilePhoneBasicFunction extends IMobilePhoneSystem {
    // 打电话
    void call();
    // 发短信
    void sendMessage();
}
public class XPhone implements IMobilePhoneBasicFunction{
  //....
}

使用 extends 这种简单的方式可以对接口进行继承。

空接口

空接口,顾名思义,没有任何行为限制的接口,如:

public interface IMobilePhone{
}

这样的接口也有它的作用,可以理解为对某一些类打了个标记,后续的某些操作可以以判断是否实现了某个接口为依据。比如常见的两个空接口 SerializableCloneable.

  • Serializable:用于标记类可以被序列化。

  • Cloneable:用于标记类可以被克隆。

Java 接口实现特点

  1. 一个类可以实现多个接口。
  2. 接口可以继承接口。

接口和类和抽象类区别

接口和抽象类的区别。

区别 接口 抽象类
继承 使用 implements 关键字实现 使用 extends 关键字实现
定义 通常定义了一组规范,规范要具体的行为 定义了一些抽象方法,但也可以包含具体方法
方法 通常方法都是抽象的,不能有具体实现,(静态方法、默认方法比较特殊)。 可以定义抽象方法,也可以包含具体方法
实现 接口不能实例化,接口可以被类实现 不能被实例化,只能被类继承
多继承 类可以实现多个接口 类只能继承一个抽象类
特点 用于解耦程序,提高代码的复用性和灵活性 用于提供一些通用的行为和属性,可以被具体类继承和扩展

接口和类的区别。

区别 接口
定义 通常只定义了一些行为规范 定义了一些属性和方法,可以包含具体行为实现
多继承 可以实现多个接口 只能继承一个类
实例化 不能被实例化,只能被类实现 可以被实例化,创建多个对象

一如既往,文章中代码存放在 Github.com/niumoo/javaNotes.