【Java】接口(Interface)

意义

1. 规范行为:定义契约

接口只定义方法的规范(方法名、参数、返回值) ,不提供实现。

类在实现接口时必须提供这些方法的实现,因此接口起到约束和规范的作用。

2. 多态性

接口是 Java 实现多态的重要机制之一。

通过接口类型引用对象,可以在不修改代码的情况下替换实际实现,提升代码的灵活性与扩展性

3. 多重继承的补充

Java 类不能多继承,但可以实现多个接口

接口弥补了单继承的不足,让类可以同时具备多种能力。

4. 解耦与模块化

接口将"做什么"与"怎么做"分离,使代码结构更松散耦合,方便替换实现、单元测试、维护与重构。

5. API 设计的基础

Java 中许多框架(如 Servlet、JDBC、Spring)广泛使用接口来统一标准,让不同厂商或开发者提供不同实现而不影响使用。

定义格式

java 复制代码
[public/缺省] interface 接口名 [extends 其他接口...] {
    // 常量(隐式的 public static final 可省略)
    // 抽象方法(隐式的 public abstract 可省略,不能有{})
    // 默认方法(default  Java 8+  隐式的 public 可省略)
    // 静态方法(static   Java 8+  隐式的 public 可省略)
    // 私有方法(private  Java 9+  必须有函数体,可为空)
}

// 接口中没有构造函数、初始化块,因为没有成员变量需要动态初始化
java 复制代码
public interface Flyable {
    // int MAX_HEIGHT;          编译错误
    // private/protected ...;   编译错误
    int MAX_HEIGHT = 1000; 

    void fly(); // 抽象方法
    void fly2() {}; // 编译错误

    // private/protected default ...     编译错误
    default void start() {
        System.out.println("Start flying...");
    }

    static void check() {
        System.out.println("Checking...");
    }
    
    private static void checks() {
        System.out.println("Checkings...");
    }

    private void helper() {  // Java 9+
        System.out.println("Helper");
    }
}

!NOTE

接口也会被编译成.class文件,但一定要明确它并不是类,也是一种引用数据类型。

接口的实现

类实现接口与继承类似,使用 implements关键字。

Java 不支持多继承类,但支持多实现接口。

java 复制代码
[修饰符] class 实现类 implements 接口1, 接口2, 接口3, ... {
	// 必须重写接口中所有抽象方法。如果实现类是抽象类,可以不重写。
  	// 可以重写接口中默认方法,要去掉default。不重写时,直接继承 default 方法。
}

实现类可以继承父类同时实现接口,必须继承在前。

java 复制代码
[修饰符] class 实现类 extends 父类 implements 接口1, 接口2, 接口3, ... {
    ...
}
  • 当一个类实现接口时,该类必须实现接口中的所有抽象方法。否则这个类必须声明为abstract
  • 接口里的静态方法/常量必须用接口名(接口名.xxx)调用,不能被实现类继承或重写,不能通过实现类调用。

接口的继承

  • 接口之间可以继承,使用 extends 关键字。
  • 一个接口可以继承多个接口(接口多继承)。
  • 接口继承的是抽象方法、默认方法、静态方法和常量。
java 复制代码
interface A {
    void methodA();
}

interface B extends A {
    void methodB();
}

interface C extends A, B {
    void methodC();
}

// 实现 C 的类
class MyClass implements C {
    @Override
    public void methodA() {
        System.out.println("A 方法实现");
    }

    @Override
    public void methodB() {
        System.out.println("B 方法实现");
    }

    @Override
    public void methodC() {
        System.out.println("C 方法实现");
    }
}

public class Test {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        obj.methodA();
        obj.methodB();
        obj.methodC();
    }
}
  • 类实现接口时,需要实现接口继承链中所有的抽象方法。
  • 子接口可重写父接口的默认方法,不要去掉default

接口与实现类

接口本身不能直接创建对象,但可以通过实现类、匿名内部类、lambda 表达式(函数式接口)来创建接口的实例。

java 复制代码
InterfaceA obj = new InterfaceA(); // ❌ 错误:接口不能直接实例化
java 复制代码
interface A {
    void run();
}

class B implements A {
    public void run() {
        System.out.println("running");
    }
}

A obj = new B(); // ✔️ OK
obj.run();
java 复制代码
A obj = new A() {
    @Override
    public void run() {
        System.out.println("running");
    }
};
java 复制代码
@FunctionalInterface
interface A {
    void run();
}

A obj = () -> System.out.println("running"); // ✔️ OK

🌠类实现接口,类似于继承。因此,接口类型的变量与实现类对象之间可构成多态引用。

java 复制代码
interface Animal {
    void cry();
}

class Dog implements Animal {
    public void cry() {
        System.out.println("Dog barks");
    }
}

Animal a = new Dog(); // 多态引用
a.cry();              // 调用 Dog 的实现

相关冲突问题

0、接口之间抽象方法重名

  • 两个或多个接口包含相同签名的抽象方法时,子类只需实现一次。
java 复制代码
interface A {
    void run();
}

interface B {
    void run();
}

class C implements A, B {
    @Override
    public void run() {
        System.out.println("run from C");
    }
}

public class Demo3 {
    public static void main(String[] args) {
        new C().run();
    }
}

1、父类方法 vs. 接口抽象方法冲突

  • 如果父类中已经提供了某个方法的实现,而接口中声明了同名同参数的抽象方法甚至是提供了默认方法,则父类方法优先。子类不需要重新实现接口中的该抽象方法或覆盖接口的默认方法。
java 复制代码
interface A {
    void hello();  // 抽象方法
    // or
    /*
    default void hello() {  // 默认方法
        System.out.println("Hello from A");
    }
    */
}

class Parent {
    public void hello() {
        System.out.println("Hello from Parent");
    }
}

class Child extends Parent implements A {
    // 不需要实现 A.hello(),因为 Parent 已提供实现
    // 或覆盖接口的默认方法
}

public class Demo {
    public static void main(String[] args) {
        new Child().hello();     // Hello from Parent
    }
}

2、多个接口间默认方法重名冲突

  • 当多个接口具有相同签名的默认方法 时,子类必须显式地覆盖方法,否则编译错误;子接口本身不会编译错误,但实现这个子接口的类必须解决方法冲突,或在子接口中重新定义默认实现。
  • 子类可以选择调用某个接口的默认实现,写法InterfaceName.super.methodName();
java 复制代码
interface A {
    default void hello() {
        System.out.println("Hello from A");
    }
}

interface B {
    default void hello() {
        System.out.println("Hello from B");
    }
}

class C implements A, B {
    @Override
    public void hello() {
        // 解决冲突:必须明确选择一个父接口的默认方法
        A.super.hello();
        // 或 B.super.hello();
    }
}
java 复制代码
interface C extends A, B {
    // 编译通过:不强制重写 hello()
    // 但实现该接口的类必须解决冲突
}

class D implements C {
    // 编译错误:hello() 有冲突,必须解决
}

class D implements C {
    @Override
    public void hello() {
        // 显示调用哪个接口的默认实现
        A.super.hello();  // 或者 B.super.greet();
    }
}

// or
interface C extends A, B {
    @Override
    default void hello() {
        A.super.hello(); // 或者 B.super.greet(),或自己写
    }
}

class D implements C {
    // 不需要重写 hello()
}

3、常量冲突

  • 如果多个接口中存在同名常量,或父类与父接口中存在同名常量,将会发生字段隐藏冲突。
java 复制代码
public class Father {
    int x = 1;
}
java 复制代码
public interface A {
    int x = 2;
    int y = 2;
}
java 复制代码
public interface B {
    int x = 3;
}
java 复制代码
public class Child extends Father implements A, B {
    public void method() {
//        System.out.println("x = " + x); // 模糊不清
        System.out.println("super.x = " + super.x);
        System.out.println("A.x = " + A.x);
        System.out.println("B.x = " + B.x);
        System.out.println("y = " + y);  // 没有重名问题,可以直接访问
    }
}
java 复制代码
interface A {
    int VALUE = 10;
}

interface B {
    int VALUE = 20;
}

class C implements A, B {
    public void print() {
        // 必须用接口名区分
        System.out.println(A.VALUE);
        System.out.println(B.VALUE);
    }
}
相关推荐
h***01541 小时前
SpringBoot 集成 Activiti 7 工作流引擎
java·spring boot·后端
g***78911 小时前
Java语法进阶
java·开发语言·jvm
w***4811 小时前
Spring Boot 整合 Druid 并开启监控
java·spring boot·后端
星尘库1 小时前
怎么实现js混淆加密 每隔一段时间 会失效 需要重新加密使用
java·服务器·前端
白露与泡影1 小时前
Java面试题2025最新、最全、最细(附答案)
java·开发语言
D***y2011 小时前
SpringCloud篇(配置中心 - Nacos)
java·spring·spring cloud
weixin_515039791 小时前
互联网大厂面试:程序员二狗的搞笑经历
java·学习·面试·程序员·互联网·技术·故事
q***D4431 小时前
Navicat 连接 SQL Server 详尽指南
java