01、接口(Interface)

  • 在 Java 中,接口是一种完全 / 彻底 抽象类型
    • 使用 interface 关键字代替 class 关键字的
  • 也有资料上说 接口不是,而是对希望实现这个接口一组需求 / 约束 / 契约 / 协议
    • 经常听到某个服务提供商说:如果你的 符合某个特定接口,我就会履行这项服务。
      • 接口有一个更加形象的叫法,那就是协议contract )。
  • 接口中,更多声明方法
    • 因此,接口 本质方法声明的集合
  • 当然,有些接口也有没有明确说明额外要求
    • 如:Comparable 接口compareTo 方法
  • 调用 x.compareTo(y) 时,必须能比较两个对象,并返回比较的结果,即 x 和 y 哪一个更大。
    • 当 x 小于 y 时,返回一个负数;当 x 其等于 y 时,返回 0;否则返回一个正数。

一、接口 – 用implements表示一种协议(contract)关系


1、基本结构


  • 接口:使用 interface 修饰的类
package org.rainlotus.materials.javabase.a04_oop.interfaces;

/**
 * @author zhangxw
 */
public interface Flyable {
    /** 字段必须指定初始值:省略了 public static final */
    String DESC = "能飞接口";

    /** 抽象方法(无实现):省略了 public abstract */
    abstract void fly();

    /** 新增了默认方法:省略了 public
            为了避免在接口中新增一个方法,之前所有的实现类都要去实现这个方法。*/
    default void takeOff() {
        System.out.println("准备起飞...");
    }

    /** 新增了静态方法:省略了 public。
            随着 JDK 的发展,发现类库中出现了很多这样成组的 API。
                Path 接口和 Paths 工具类、Collection 接口和 Collections 工具类
                增加了静态方法后,可以减少很多这样的工具类。 */
    static void logFlight() {
        System.out.println("记录飞行日志");
    }

    /** 私有方法(Java 9+,接口内部复用代码) */
    private void internalLog(String message) {
        System.out.println("[LOG] " + message);
    }
}


public class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("鸟儿扇动翅膀飞行");
    }
}

public class Airplane implements Flyable {
    @Override
    public void fly() {
        System.out.println("飞机通过引擎飞行");
    }
}

2、接口的设计目的


  • 1、定义行为规范
    • 即:定义清晰的契约,解耦实现。
    • 强调“能力”而非“身份”(如:Flyable 表示“能飞”),与实现类的类型无关。
      • 如:飞机 都能飞。
  • 2、解耦与多态
    • 通过接口隔离实现细节,支持灵活替换(如:依赖注入)。
    • 即:通过多实现支持灵活扩展
  • 3、替代多继承
    • Java 不支持类多继承,但可通过多接口实现扩展功能。

  • 接口实现了约定实现相分离,可以降低代码间的耦合性提高代码的可扩展性
    • 如:策略模式

3、核心特性


  • 1、接口不能有构造器不能有初始化块
  • 2、接口里的 field 都是必须有初始值静态常量。默认有 3 个修饰符public static final
  • 3、接口中抽象方法没有方法体方法),默认有 2 个修饰符public abstract
  • 4、接口中 default 方法default 修饰的方法体方法),默认有 1 个修饰符public
  • 5、接口中 static 方法static 修饰的方法体方法),默认有 1 个修饰符public
  • 6、接口里的内部类、内部接口、内部枚举、默认 2 个修饰符public static
  • 7、一个接口同时继承 N 个直接父接口

4、接口 的使用


  • 通过 实现,在子类中,实现抽象方法。
class Bird implements Flyable{

    @Override
    public void fly() {
        System.out.println("会飞翔");
    }

    public static void main(String[] args) {
        Flyable flyable = new Bird();
        flyable.fly();
        System.out.println(Flyable.DESC);
    }
}
  • 通过创建 接口 的 匿名内部类,在内部类中,实现抽象方法。
class Test {
    public static void main(String[] args) {
        Flyable flyable = new Flyable() {
            @Override
            public void fly() {
                System.out.println("会飞翔");
            }
        };

        flyable.fly();
        System.out.println(Flyable.DESC);
    }
}

5、Java 8+ 对接口的增强


  • 默认方法:允许在接口中提供方法默认实现避免破坏已有实现类。
public interface Vehicle {
    default void start() {
        System.out.println("车辆启动");
    }
}

public class Car implements Vehicle {} // 无需实现 start()

  • 静态方法:直接通过接口名调用,用于工具方法
public interface MathUtils {
    static int add(int a, int b) {
        return a + b;
    }
}

int sum = MathUtils.add(3, 5); // 直接调用
  • 私有方法(Java 9+):在接口内部复用代码
public interface Logger {
    private void log(String level, String message) {
        System.out.println("[" + level + "] " + message);
    }
    
    default void info(String message) {
        log("INFO", message);
    }
    
    default void error(String message) {
        log("ERROR", message);
    }
}

二、接口的使用场景


1、标记接口(Marker Interface)


  • 定义无任何方法的接口,仅用于标识类型
    • 如:Serializable、Cloneable)。
public interface Loggable {} // 标记可记录日志的类

public class User implements Loggable {
    // 类实现
}

2、函数式接口(Functional Interface)


  • 定义仅有一个抽象方法的接口,可用 @FunctionalInterface 注解标记。
    • 支持 Lambda 表达式。
@FunctionalInterface
interface StringProcessor {
    String process(String input);
    
    default StringProcessor andThen(StringProcessor after) {
        return input -> after.process(this.process(input));
    }
}


public static void main(String[] args) {
    StringProcessor toUpper = s -> s.toUpperCase();
    StringProcessor addExclamation = s -> s + "!";
    
    StringProcessor pipeline = toUpper.andThen(addExclamation);
    System.out.println(pipeline.process("hello")); // 输出 "HELLO!"
}

3、接口的多重继承


  • 接口可继承多个父接口:
public interface A { void methodA(); }
public interface B { void methodB(); }
public interface C extends A, B { void methodC(); }

public class D implements C {
    @Override public void methodA() {}
    @Override public void methodB() {}
    @Override public void methodC() {}
}

4、接口 与 工厂模式


  • 对象创建解耦
interface DatabaseConnection {
    void connect();
}

class MySQLConnection implements DatabaseConnection {
    public void connect() { System.out.println("MySQL 连接"); }
}

interface ConnectionFactory {
    DatabaseConnection createConnection();
}

class MySQLFactory implements ConnectionFactory {
    public DatabaseConnection createConnection() {
        return new MySQLConnection();
    }
}

// 使用
ConnectionFactory factory = new MySQLFactory();
DatabaseConnection conn = factory.createConnection();
conn.connect();

5、接口与事件驱动架构


  • 观察者模式(Observer Pattern)
interface EventListener {
    void onEvent(Event event);
}

class EventDispatcher {
    private List<EventListener> listeners = new ArrayList<>();
    
    public void addListener(EventListener listener) {
        listeners.add(listener);
    }
    
    public void fireEvent(Event event) {
        for (EventListener listener : listeners) {
            listener.onEvent(event);
        }
    }
}

// 使用
EventDispatcher dispatcher = new EventDispatcher();
dispatcher.addListener(event -> System.out.println("事件处理: " + event));
dispatcher.fireEvent(new Event("data_updated"));

6、策略模式 – 完全满足 开闭原则


  • 定义算法族,支持运行时动态切换
public interface PaymentStrategy {
    void pay(double amount);
}

public class CreditCardPayment implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("信用卡支付:" + amount);
    }
}

public class ShoppingCart {
    private PaymentStrategy strategy;
    
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void checkout(double amount) {
        strategy.pay(amount);
    }
}

// 使用示例
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100.0);

三、抽象类 vs 接口


1、设计层面的对比


抽象类:描述“是什么”(is-a 关系)

  • 本质:抽象类是对抽象,强调从属关系
    • 如:Animal 是 Dog 的基类,表示“狗是一种动物”。
  • 代码复用:通过继承共享公共代码(如:字段、方法实现)。
  • 控制子类行为:通过抽象方法强制子类实现特定逻辑,或通过模板方法定义算法骨架

接口:描述“能做什么

  • 本质:接口是对行为抽象,强调能力扩展
    • 如:Flyable 接口表示“能飞行”,无论实现者是还是飞机
  • 解耦与多态:通过接口隔离实现细节,支持灵活替换(如:依赖注入)。
  • 多继承替代:Java 不支持多继承,但可通过多接口实现扩展功能。

  • 从类的继承层次上来看:
  • 1、抽象类是一种自下而上的设计思路。
    • 先有子类代码重复,然后,再抽象成上层的抽象类
  • 2、接口是一种自上而下的设计思路。
    • 编程时,一般都是先设计接口,再去考虑具体的实现

2、抽象类与接口的选择?


  • 如果要表示一种 is-a 的关系 (是一个),并且是为了解决代码复用的问题,就用抽象类
  • 如果要表示一种 contract 的关系 (协议),并且是为了解决抽象代码复用的问题,就用接口
决策因素选择抽象类选择接口
需要共享代码✅ 抽象类可提供具体方法实现❌ 接口在 Java 8 前只能有抽象方法
需要多继承❌ Java 单继承限制✅ 类可实现多个接口
需要管理状态✅ 抽象类可定义实例变量❌ 接口只能有常量
需要构造器逻辑✅ 抽象类可定义构造器初始化状态❌ 接口无构造器
定义行为规范❌ 更适合定义类别层次✅ 接口天然适合定义行为
未来扩展性❌ 修改抽象类可能影响所有子类✅ 接口通过默认方法扩展更灵活

3、语法与功能对比


特性抽象类接口
关键字abstract classinterface
继承/实现单继承(extends)多实现(implements)
构造器✅ 可定义,用于初始化成员变量❌ 不能定义
成员变量可包含实例变量(非 final)和常量仅常量:默认 public static final
方法类型抽象方法、具体方法、静态方法、私有方法Java 8-:抽象方法、
Java 8+:支持默认方法、静态方法;
Java 9+:支持私有方法
访问修饰符支持 public、protected、private`、包级私有方法默认 public。
Java 9+:方法支持 private)
设计目的定义类的层次结构是什么),提供部分实现定义行为契约能做什么),支持多态扩展
典型应用模板方法模式、共享状态管理、
复杂对象初始化
策略模式、回调机制、
API 设计、依赖注入

四、接口设计原则总结

原则说明
单一职责原则每个接口应专注于单一功能领域。
如:Runnable 只定义运行,不混合其他职责。
接口隔离原则避免庞大臃肿的接口,拆分细化。
如:List 与 RandomAccess 接口分离。
里氏替换原则子类必须完全实现接口 契约,行为可替换父接口
依赖倒置原则高层模块依赖抽象接口,而非具体实现
开闭原则通过新增接口实现扩展,而非修改已有接口

五、常见问题


1、接口中可以有哪些元素?


A、接口不能有构造器不能有初始化块

B、接口里的field,默认有3个修饰符:public static final

无论你写于不写,反正都有。

【接口里的 field,声明必须指定初始值

原因:final 修饰的类变量只能在声明时、静态初始化块中指定初始值

又由于接口不包含初始化块,所以只能在声名时指定初始值。

C、接口里的 抽象方法默认有 2 个修饰符 public abstract

无论你写于不写,反正都有。

接口里的方法不可能是 static,因为接口里的方法默认有 abstract 修饰。

D、接口里的 内部类、内部接口、内部枚举、默认也有两个修饰符:public static

无论你写于不写,反正都有。

E、一个接口可以有N个直接父接口。

有了接口:

A、接口可用于定义常量

B、接口不能直接创建实例

C、接口最大的用途就是让其它类来实现它。

2、接口里面可以写方法实现吗?


  • Java 8-:抽象方法,不可以写方法实现。
  • Java 8+:支持默认方法、静态方法,可以写方法实现
  • Java 9+:支持私有方法,可以写方法实现

3、接口中只能定义常量和抽象方法吗?


  • JDK1.7 之前,接口中只能定义 静态常量公共的抽象方法
  • JDK1.8 中,接口中可以定义 默认方法静态方法
  • JDK1.9 中,接口中可以定义 私有方法

4、接口能不能被 new ?


  • 接口也可以直接 new,但要配合内部类来使用,一般是不可以 new 的。

5、接口默认方法和静态方法是什么?


public interface T001_InterfaceWithDefaultMethod {
    default void defaultMethod(){
        System.out.println("接口的 default 方法");
    }

    static void staticDefaultMethod(){
        System.out.println("接口的 static 方法");
    }

    static void main(String[] args) {
        staticDefaultMethod();
        System.out.println(123);
    }
}

class InterfaceImpl implements T001_InterfaceWithDefaultMethod{

    @Override
    public void defaultMethod() {
        System.out.println("实现类的 default 方法");
    }

    public static void main(String[] args) {
        T001_InterfaceWithDefaultMethod impl = new InterfaceImpl();
        impl.defaultMethod();
    }
}

6、接口为什么新增了默认方法和静态方法?


  • 为了避免在接口中新增一个方法,之前 所有的实现类都要去实现这个方法

  • 随着 JDK 的发展,发现类库中出现了很多这样成组的 API

    • Path 接口和 Paths 工具类、Collection 接口和 Collections 工具类
    • 增加了接口静态方法后,可以减少很多这样的工具类。

7、接口默认方法有哪些注意的问题?


  • 方法要有 default 进行修饰。
  • 方法不能用 private 修饰。默认是省略了 public 修饰符。
  • 方法必须要有方法体

8、解决 接口 默认方法 多继承 冲突 问题


  • 1、超类优先。
    • 如果超类提供了一个具体方法,同名而且有相同参数类型的默认方法会被忽略。
package org.rainlotus.materials.javabase.a04_oop.interfaces;

/**
 * 接口中,默认方法冲突
 * @author zhangxw
 */
public class InterfaceDefaultMethodConflict {
    public static void main(String[] args) {
        C c = new C();
        // 输出:父类 A 中的 foo 方法!!!
        c.foo();
    }
}

class A { public void foo(){System.out.println("父类 A 中的 foo 方法!!!");}}
interface B { default void foo() { System.out.println("接口 B 中的 foo 默认方法!!!"); } }

class C extends A implements B {
}

  • 2、接口冲突。
    • 如果一个接口提供了一个默认方法。另一个接口提供了一个同名而且参数类型相同方法 (不论是否是默认方法),必须覆盖 这个方法来解决冲突。
package org.rainlotus.materials.javabase.a04_oop.interfaces;

/**
 * 接口中,默认方法冲突
 * @author zhangxw
 */
public class InterfaceDefaultMethodConflict {
    public static void main(String[] args) { }
}

interface A { default void foo(){System.out.println("接口 A 中的 foo 默认方法!!!");}}
interface B { default void foo() { System.out.println("接口 B 中的 foo 默认方法!!!"); } }

class C implements A,B {
    /**
     * 必须重写 冲突的方法
     */
    @Override
    public void foo() {
        System.out.println("自己实现 foo 方法");
        B.super.foo();
        A.super.foo();
    }
}
interface A { void foo();}
interface B { default void foo() { System.out.println("B"); } }

interface C extends A, B {

    /**
     * 必须重写 冲突的方法
     */
    @Override
    default void foo() {
        System.out.println("");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值