揭开Java接口的神秘面纱:通往代码优雅之路

目录

一、引言

什么是接口?

二、Java 接口基础及其特性

接口定义的语法如下:

1.接口中的方法(抽象方法的概念)

2。接口中的默认方法和静态方法

3.接口中每一个方法都是public的抽象方法, 即接口中的方法会被隐式的指定为 public abstract

4.重写接口中方法时,不能使用默认的访问权限 

5接口中的常量

6.接口类型是一种引用类型,但是不能直接new接口的对象

7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

8. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

9. jdk8之后:接口中还可以包含default方法和static方法,可以进行具体实现

10.接口也可以发生向上转型,也可以发生动态绑定,也可以发生多态

ps:接口这样设计有什么好处呢?

三、实现接口

如何实现一个接口(包括一个或多个接口)

接口与继承类的区别和联系

示例:

四、接口的实际应用

1. 适配器模式(Adapter Pattern)

2. 工厂模式(Factory Pattern)

 3.观察者模式(Observer Pattern)

五、接口与抽象类的区别 


一、引言

什么是接口?

在 Java 中,接口(Interface)是一种抽象类型,它定义了一组方法和常量,但不提供任何具体的实现。接口充当一种契约的角色,规定了类必须遵守的协议。任何实现了接口的类都必须实现接口中定义的所有方法。

接口与 Java 编程中的角色和重要性

接口在 Java 编程中扮演着至关重要的角色。它们支持多重继承的概念,允许一个类实现多个接口。这种设计模式鼓励代码的模块化和可重用性,并提高了代码的可维护性和可扩展性。此外,接口还被广泛用于定义通用的编程规范,使不同的类能够以统一的方式进行交互。

二、Java 接口基础及其特性

定义接口的语法

在 Java 中,使用 interface 关键字定义接口。

接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口。

接口定义的语法如下:

[可见性] interface 接口名称 [extends 其他接口名] {
    // 常量定义
    // 方法声明
}

1.接口中的方法(抽象方法的概念)

接口中定义的方法都是隐式抽象的,也就是说,它们没有方法体。这些方法必须由实现该接口的类来提供具体的实现。例如:

public interface Walkable {
    void walk(); // 抽象方法,没有方法体
}

2。接口中的默认方法和静态方法

从 Java 8 开始,接口可以定义默认方法和静态方法。默认方法提供了一个默认的实现,可以被实现该接口的类继承或重写。静态方法则可以在接口内部直接调用,无需实例化接口

interface Walkable {
    void walk(); // 抽象方法
    default void run() { // 默认方法
        System.out.println("Running...");
    }
    static void printInfo() { // 静态方法
        System.out.println("This is the Walkable interface.");
    }
}

3.接口中每一个方法都是public抽象方法, 即接口中的方法会被隐式的指定为 public abstract

(只能是 public abstract,其他修饰符都会报错,如protected abstract和private abstract )

与第九点进行区分(jdk8之后有扩展)

4.重写接口中方法时,不能使用默认的访问权限 

5接口中的常量

接口中定义的变量都是隐式的 public static final 类型(当然你也可显示的写出来,只不过编译器会告诉你那是多余的),也就是常量。常量的值必须在定义时指定,后续不能修改。

interface Constants {
    int MAX_VALUE = 100; // 常量
    String MESSAGE = "Hello, World!";
}

 

6.接口类型是一种引用类型,但是不能直接new接口的对象

7. 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class

8. 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类

9. jdk8之后:接口中还可以包含default方法和static方法,可以进行具体实现

public interface duck {
    void eat();
    default void run(){
        //具体实现
    };
    static void fly(){
        //具体实现
    };
}

ps:

1.(private方法在IDE上不会报错,但是被private修饰了,其他类就没有能力使用那个类,等于形同虚设,所以不要用private)。

2.接口中不可以有默认方法,即public/protected void run(){}

10.接口也可以发生向上转型,也可以发生动态绑定,也可以发生多态

ps:接口这样设计有什么好处呢?

时刻牢记多态的好处, 让程序猿忘记类型. 有了接口之后, 类的使用者就不必关注具体类型,

而只关注某个类是否具备某种能力 .

三、实现接口

如何实现一个接口(包括一个或多个接口)

要实现一个接口,类必须使用 implements 关键字,并提供接口中所有抽象方法的具体实现。一个类可以同时实现多个接口,只需用逗号分隔接口名即可。

class MyClass implements Interface1, Interface2 {
    // 实现 Interface1 中的方法
    // 实现 Interface2 中的方法
}

接口与继承类的区别和联系

  • 继承是一种"是一个"的关系,子类继承了父类的所有属性和方法。而实现接口是一种"能-做"的关系,类实现了接口中定义的协议。
  • 子类和父类之间是extends 继承关系,类与接口之间是 implements 实现关系。
  • 一个类只能继承一个父类,但可以实现多个接口
  • 接口只定义了方法的签名,实现由实现类提供。而抽象类可以包含具体的方法实现。

示例:

创建接口并实现它的具体类

让我们创建一个 Flyable 接口,并实现一个 Bird 类:

// 定义接口
interface Flyable {
    void fly();
    void landing();
}

// 实现接口
class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("The bird is flying!");
    }

    @Override
    public void landing() {
        System.out.println("The bird is landing.");
    }

    public static void main(String[] args) {
        Bird bird = new Bird();
        bird.fly();
        bird.landing();
    }
}

四、接口的实际应用

接口作为 API 的契约

接口在定义 API 时扮演着重要角色。它们定义了一组方法,作为与外部系统交互的契约。任何实现该接口的类都必须遵守这个契约,从而确保API的一致性和可靠性。

使用接口提高模块化和可替换性

接口支持模块化设计,将系统划分为独立的模块,每个模块实现一个或多个接口。这种设计方式增强了代码的可维护性和可扩展性。此外,接口还提高了代码的可替换性,因为只要实现相同的接口,一个模块就可以被另一个模块替换。

设计模式中的接口应用

接口在多种设计模式中发挥着关键作用,例如:

  • 适配器模式: 使用接口将不兼容的类包装起来,提供统一的接口。
  • 工厂模式: 工厂类返回实现特定接口的对象实例。
  • 观察者模式: 观察者和被观察者之间通过接口进行通信。

1. 适配器模式(Adapter Pattern)

适配器模式用于将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以一起工作。

假设我们有一个LightningPhone接口,它有一个rechargeuseLightning方法,我们还有一个MicroUsbPhone接口,它有一个rechargeuseMicroUsb方法。我们需要一个适配器使得MicroUsbPhone可以通过LightningPhone接口使用。

接口定义:

interface LightningPhone {
    void recharge();
    void useLightning();
}

interface MicroUsbPhone {
    void recharge();
    void useMicroUsb();
}

适配器实现: 

// 适配器实现 LightningPhone 接口
class LightningToMicroUsbAdapter implements LightningPhone {
    private MicroUsbPhone microUsbPhone;

    public LightningToMicroUsbAdapter(MicroUsbPhone phone) {
        this.microUsbPhone = phone;
    }

    @Override
    public void recharge() {
        microUsbPhone.recharge();
    }

    @Override
    public void useLightning() {
        microUsbPhone.useMicroUsb();
        System.out.println("Lightning connected via Micro USB.");
    }
}

2. 工厂模式(Factory Pattern)

工厂模式用于创建对象,允许接口指定对象的类型,但由子类决定实例化哪一个类。这样,工厂方法在类的实例化过程中扮演了“工厂”的角色。

假设我们有一个Phone接口和两个实现了Phone接口的类:AndroidPhoneIPhone

接口定义:

interface Phone {
    void makeCall();
    void sendSMS();
}

class AndroidPhone implements Phone {
    public void makeCall() {
        System.out.println("Android call");
    }

    public void sendSMS() {
        System.out.println("Android SMS");
    }
}

class IPhone implements Phone {
    public void makeCall() {
        System.out.println("iPhone call");
    }

    public void sendSMS() {
        System.out.println("iPhone SMS");
    }
}

工厂类实现: 

class PhoneFactory {
    public Phone getPhone(String type) {
        if (type.equalsIgnoreCase("iPhone")) {
            return new IPhone();
        } else if (type.equalsIgnoreCase("Android")) {
            return new AndroidPhone();
        }
        return null;
    }
}

 3.观察者模式(Observer Pattern)

观察者模式用于建立一种对象与对象之间的依赖关系,一个对象改变状态时,所有依赖于它的对象都会得到通知并被自动更新。

接口定义:

interface Observer {
    void update(String message);
}

interface Subject {
    void attach(Observer o);
    void detach(Observer o);
    void notifyUpdate(String message);
}

模式实现: 

class NewsAgency implements Subject {
    private List<Observer> observers = new ArrayList<>();

    public void attach(Observer o) {
        observers.add(o);
    }

    public void detach(Observer o) {
        observers.remove(o);
    }

    public void notifyUpdate(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

class NewsChannel implements Observer {
    private String news;

    @Override
    public void update(String news) {
        this.news = news;
        System.out.println("NewsChannel updated: " + news);
    }
}

五、接口与抽象类的区别 

核心区别 : 抽象类中可以包含普通方法和普通字段 , 这样的普通方法和字段可以被子类直接使用 ( 不必重写 ), 而接口中 不能包含普通方法 , 子类必须 重写所有的抽象方法
如下代码
class Animal{
    protected String name;
    public Animal (String name){
    this.name = name;
 }
}

此处的 Animal 中包含一个 name 这样的属性, 这个属性在任何子类中都是存在的. 因此此

处的 Animal 只能作为一个抽象类, 而不应该成为一个接口.

 


感谢您耐心阅读这篇关于Java接口的文章!如果这些内容对您有所启发,或者您有更多的见解和疑问,欢迎在下方评论区留言分享您的想法。交流和讨论可以帮助我们共同进步!

如果您喜欢这篇文章,请不要吝啬您的点赞👍,您的每一个赞都是对我写作的最大鼓励。同时,您可以收藏🌟这篇博客,方便日后查阅或与朋友分享。

再次感谢您的阅读与支持!期待在评论区与您的精彩互动!💬

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值