14. 接口(适配器设计模式)

接口

  • 接口
    • 1. 定义格式
    • 2. 成员特点
      • 2.1 成员方法
      • 2.2 默认方法
      • 2.3 静态方法
      • 2.4 变量
    • 3. 接口的实现
      • 3.1 实现规则
      • 3.2 实现格式
        • 3.2.1 单实现格式
        • 3.2.2 多实现格式
      • 3.3 接口的继承
        • 3.3.1 接口与类的继承
        • 3.3.2 接口与接口的继承
    • 4.类与接口的区别
    • 5. 注意事项
  • 适配器设计模式

接口

接口(Interface)是Java中的一种引用类型,它定义了一组方法的规范,但没有具体的实现。

接口可以看作是一个规则,规定了实现该接口的类需要提供哪些方法,并且定义了方法的输入和输出。

1. 定义格式

接口(Interface)的定义格式如下:

public interface 接口名 {
    // 声明常量

    // 声明抽象方法

    // 声明默认方法

    // 声明静态方法
}

接口的名字通常使用大写字母开头,按照命名规范使用驼峰命名法。

例如:一个定义 Animal 接口

public interface Animal {
    // 声明常量
    int LEGS = 4;

    // 声明抽象方法
    void eat();

    void sleep();

    // 声明默认方法
    default void move() {
        System.out.println("Animal is moving.");
    }

    // 声明静态方法
    static void breathe() {
        System.out.println("Animal is breathing.");
    }
}

上述示例中,定义了一个 Animal 接口,该接口包含了常量 LEGS、抽象方法 eat()sleep(),以及默认方法 move() 和静态方法 breathe()

接口中的常量默认为 `public`、`static`、`final`,可以直接通过接口名访问。

2. 成员特点

2.1 成员方法

成员方法的格式:

[访问修饰符] 返回类型 方法名([参数列表]);
  • 成员方法在接口中默认为抽象方法,不需要使用 abstract 关键字进行修饰。

  • 方法默认为 public 访问权限,可以省略 public 关键字。

  • 实现类必须提供方法的具体实现。

    示例:

    public interface Animal {
        void eat();
        void sleep();
    }
    

2.2 默认方法

默认方法的格式:

default 返回类型 方法名([参数列表]) {
    // 默认方法的具体实现
}
  • 默认方法使用 default 关键字进行修饰。

  • 默认方法可以有具体的实现代码。

  • 实现类可以选择是否覆写默认方法。

    示例:

    public interface Animal {
        void eat();
        void sleep();
        default void move() {
            System.out.println("Animal is moving.");
        }
    }
    

2.3 静态方法

静态方法的格式:

static 返回类型 方法名([参数列表]) {
    // 静态方法的具体实现
}
  • 静态方法使用 static 关键字进行修饰。

  • 静态方法可以直接通过接口名调用,无需通过实现类的实例来调用。

    示例:

    public interface Animal {
        void eat();
        void sleep();
        static void breathe() {
            System.out.println("Animal is breathing.");
        }
    }
    

2.4 变量

变量的格式:

[访问修饰符] [static] [final] 数据类型 常量名 =;
  • 变量默认为 publicstaticfinal 的。

  • 变量必须在声明时进行初始化,并且在后续不能被修改。

  • 变量可以添加 privateprotected 修饰,但需要显式声明为 staticfinal

    示例:

    public interface Animal {
        int LEGS = 4;
        String NAME = "Animal";
    }
    

3. 接口的实现

接口的实现是指一个类实现了一个或多个接口,并提供了接口中声明的所有方法的具体实现。

在Java中,使用关键字 `implements` 来实现接口。

接口提供了一种约定,定义了一组方法的规则,而类实现接口时则需要遵守这个规则,并提供相应的方法实现。通过实现接口,类可以获得这些方法的定义,并在需要的时候提供自己的实现。

3.1 实现规则

要实现一个接口,类需要遵循以下规则:

  1. 使用 implements 关键字后跟着要实现的接口名称。
  2. 实现接口的类必须提供接口中定义的所有方法的具体实现。
  3. 可以实现多个接口,多个接口之间使用逗号 , 分隔。

例如:

// 定义一个接口
interface Animal {
    void eat();
    void sleep();
}

// 实现Animal接口的类
class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("Cat is eating.");
    }
    
    @Override
    public void sleep() {
        System.out.println("Cat is sleeping.");
    }
}

// 实现Animal接口的类
class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("Dog is eating.");
    }
    
    @Override
    public void sleep() {
        System.out.println("Dog is sleeping.");
    }
}

// 主程序
public class Main {
    public static void main(String[] args) {
        // 创建实现了Animal接口的实例
        Cat cat = new Cat();
        Dog dog = new Dog();
        
        // 调用实现的方法
        cat.eat();
        cat.sleep();
        
        dog.eat();
        dog.sleep();
    }
}

在上面的示例中,Cat 类和 Dog 类分别实现了 Animal 接口,并提供了 eat()sleep() 方法的具体实现。然后在主程序中,我们创建了 CatDog 的实例,然后可以通过这些实例调用接口中的方法。

3.2 实现格式

在 Java 中,一个类可以实现一个或多个接口。

接口的单实现指一个类只实现一个接口,而接口的多实现指一个类实现多个接口。
3.2.1 单实现格式

单实现格式:

class ClassName implements InterfaceName {
    // 实现接口中声明的方法
    // ...
}

在单实现的情况下,类 ClassName 实现了接口 InterfaceName,并提供了接口中声明的方法的具体实现。

举例:

interface Animal {
    void eat();
}

class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("Cat is eating.");
    }
}

在这个例子中,Cat 类实现了 Animal 接口,提供了 eat() 方法的具体实现。

3.2.2 多实现格式

多实现格式:

class ClassName implements Interface1, Interface2, Interface3 {
    // 实现接口中声明的方法
    // ...
}

在多实现的情况下,类 ClassName 实现了多个接口 Interface1Interface2Interface3,并提供了这些接口中声明的方法的具体实现。

举例:

interface Swimmer {
    void swim();
}

interface Flyer {
    void fly();
}

class Duck implements Swimmer, Flyer {
    @Override
    public void swim() {
        System.out.println("Duck is swimming.");
    }

    @Override
    public void fly() {
        System.out.println("Duck is flying.");
    }
}

在这个例子中,Duck 类实现了 SwimmerFlyer 接口,提供了 swim()fly() 方法的具体实现。

3.3 接口的继承

3.3.1 接口与类的继承

接口与类的继承格式:

class SubClass extends SuperClass {
    // ...
}

其中,SubClass 是子类的名称,SuperClass 是父类的名称。

例如:

class Animal {
    public void eat() {
        System.out.println("Animal is eating.");
    }
}

class Cat extends Animal {
    public void meow() {
        System.out.println("Cat is meowing.");
    }
}

public class Main {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
        cat.meow();
    }
}

在上面的例子中,定义了一个 Animal 类,其中有 eat() 方法。接着,定义了一个 Cat 类,它继承自 Animal,并且有一个新的方法 meow()。最后,在 main() 方法中,创建了一个 Cat 对象并调用了它的 eat()meow() 方法。

3.3.2 接口与接口的继承

接口与接口的继承格式:

interface SubInterface extends SuperInterface1, SuperInterface2, ... {
    // ...
}

其中,SubInterface 是子接口的名称,SuperInterface1SuperInterface2 等是父接口的名称。

例如:

interface Shape {
    void draw();
}

interface Circle extends Shape {
    double getRadius();
}

class CircleImpl implements Circle {
    private double radius;

    public CircleImpl(double radius) {
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Drawing circle...");
    }

    @Override
    public double getRadius() {
        return this.radius;
    }
}

public class Main {
    public static void main(String[] args) {
        Circle circle = new CircleImpl(5.0);
        circle.draw();
        System.out.println("Radius: " + circle.getRadius());
    }
}

在上面的例子中,定义了一个 Shape 接口,并有一个 draw() 方法。同时,定义了一个 Circle 接口,它继承自 Shape 并有一个新的抽象方法 getRadius()。接着,在 CircleImpl 类中,实现了 Circle 接口中的 draw()getRadius() 方法。最后,在 main() 方法中,创建了一个 CircleImpl 对象,并调用了 draw()getRadius() 方法。

4.类与接口的区别

类与接口是两种不同的概念。
  1. 实现方式:

    • 类是对对象的实现,描述了对象具有的属性和方法,并提供了具体的实现代码。

    • 接口是一种约定,它定义了一组方法的签名(方法名、参数列表和返回类型),但没有提供具体的实现代码。

  2. 继承关系:

    • 一个类可以继承自另一个类,它可以拥有父类的属性和方法,并可以通过重写和扩展来定制自己的行为。

    • 一个类可以实现一个或多个接口,通过实现接口的方法来定义自己的行为,同时一个类可以继承一个类并实现多个接口。

  3. 多态性:

    • 类的实例可以通过父类引用指向子类对象,从而实现多态性。

    • 接口可以通过接口类型的引用指向实现了该接口的类的对象,也可以实现多态性。

  4. 可继承性:

    • 类可以通过继承来获取父类的属性和方法,并可以进行重写和扩展,从而实现代码的复用。

    • 接口可以通过继承其他接口的方式来扩展自己的方法,从而实现接口之间的代码复用。

  5. 实例化:

    • 类可以被实例化为对象,通过创建对象来调用类中的方法。

    • 接口不能被直接实例化,但是可以通过实现接口的类来创建该类的对象,然后通过接口引用来调用接口中的方法。

5. 注意事项

在使用接口时,有一些需要注意的事项:

  1. 接口不能被实例化:接口本身不能直接创建对象,因为接口没有提供实现。但是可以通过实现接口的类来创建对象。

  2. 接口中的方法默认为抽象方法:接口中的方法默认为抽象方法,没有方法体。实现接口的类必须提供具体的方法实现。

  3. 接口中的字段默认为常量:接口中的字段默认为 public static final,即常量。实现接口的类不可以修改接口中的常量值。

  4. 类可以实现多个接口:一个类可以实现一个或多个接口,通过逗号分隔。

  5. 接口可以继承多个接口:一个接口可以继承一个或多个接口,通过扩展关键字 extends 和逗号分隔。

  6. 接口不能实现其他接口:接口不能实现其他接口,只能继承其他接口。

     "实现"通常指的是在一个类中提供对接口中定义的方法的具体实现。
    
     实现是指在实现类中编写实际的代码,以使得类具有接口中声明的方法所描述的行为。
    
  7. 接口可以作为数据类型使用:可以使用接口作为方法的参数类型、返回值类型,或者定义接口类型的变量。

  8. 实现类必须实现接口的所有方法:如果一个类实现了某个接口,那么它必须实现接口中定义的所有方法,除非它自己也是一个抽象类。

  9. 默认方法和静态方法:Java 8 引入了接口中的默认方法和静态方法。默认方法为接口提供了方法的默认实现,而静态方法为接口提供了静态方法的实现。

  10. 接口不能包含实例状态:接口中只能包含方法和常量,不能包含实例变量。

适配器设计模式

适配器设计模式(Adapter Design Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一个接口。

适配器模式可以让不兼容的类可以一起工作,通过将不同类的接口进行适配,使得它们能够协同工作。

在客户端代码中,先通过一个适配器对象将适配者类转换为目标接口,然后客户端通过目标接口调用适配器类的方法,由适配器类再通过持有的适配者类实例来调用适配者类的不兼容方法,从而实现了目标接口和适配者类的适配。

下面假设有一个目标接口 Target,它定义了客户端所需要的接口,但是该接口与 Adaptee 接口不兼容,我们需要一个适配器来将 Adaptee 转化为 Target 接口的形式。代码如下:

// 目标接口
interface Target {
    // 客户端所需的接口
    void request();
}

// 适配者类
class Adaptee {
    // 与目标接口不兼容的接口
    void specificRequest() {
        System.out.println("适配者类的方法被调用了。");
    }
}

// 适配器类
class Adapter implements Target {
    // 持有适配者类的实例
    private Adaptee adaptee = new Adaptee();
    
    @Override
    public void request() {
        // 进行适配转换
        adaptee.specificRequest();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建一个适配器对象,将适配者类转换为目标接口
        Target adapter = new Adapter();
        
        // 客户端通过目标接口调用适配者类的方法
        adapter.request(); // 输出:适配者类的方法被调用了。
    }
}

在上述代码中,Target 接口定义了客户端所需要的接口,Adaptee 类是需要被适配的类,其接口与目标接口不兼容,即 Adaptee 中的 specificRequest 方法与 Target 中的 request 方法不同。Adapter 类是适配器类,它实现了目标接口 Target,并持有适配者类 Adaptee 的实例。Adapter 类的 request 方法将客户端的请求转发给适配者类,并进行适当的转换,以使得适配者类的接口能够与目标接口兼容。

你可能感兴趣的:(Java基础语法,java,开发语言,idea,设计模式)