认识接口和适配器设计模式

话题引入

为什么有接口?
认识接口和适配器设计模式_第1张图片
如图所示,动物类为父类,兔子,狗,青蛙为子类。当我们想为狗和青蛙设置动作属性游泳时,发现不能直接在动物父类当中定义,因为兔子不会游泳,那会想到分别在其类当中定义,这样的作法是可以的,但是有个弊端,无法限定子类当中方法书写的格式,方法不统一。所以我们会定义一个接口,定义游泳这个抽象方法,自己定义游泳规则。
认识接口和适配器设计模式_第2张图片

接口就相当于定义的规则,可以强制要求狗和青蛙类可以按照接口里面定义的规则来写,代码就统一起来了。所以当我们需要给多给类去定义规则时,就需要用到接口。

接口

就是一种规则,是对行为的抽象。

接口的定义和使用

接口用关键字interface来定义

public interface 接口名{}

接口不能实例化(创建对象)

接口和类之间是实现关系,通过implements关键字表示

public class 类名 implements 接口名 {}

接口的子类(实现类)

  1. 要么写接口中的所有抽象方法(推荐)
  2. 要么是抽象类

注意1:

接口和类的实现关系,可以单实现,也可以多实现。

public calss 类名 implements 接口名1,接口名2 {}

注意2:

实现类还可以在继承一个类的同时实现多个接口。

public class 类名 extends 父类 implements 接口名1,接口名2 {}

现在我们来实际操作一下:

编写带有接口和抽象类的标准Javabean类

青蛙 属性:名字,年龄 行为:吃虫子,游泳

狗 属性:名字,年龄 行为:吃骨头,狗刨

兔子 属性:名字,游泳 行为:吃胡萝卜

先编写父类,父类中包含它们共有的属性

public abstract class Animal {
    private String name;
    private int age;

    public Animal() {
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
	
    //每一个动物吃的东西不一样,所以不写方法体,
    //没有方法体的方法是抽象方法,要加上abstract
    public abstract void eat();
}

因为兔子不会游泳,所以游泳这个方法不能写在父类中,那么我们就要用接口来定义游泳这个规则。

public interface swim {
    //在接口里面定义规则
    public abstract void swim();
}

接口定义好,我们继续写实现类,第一个是兔子类,兔子类只需要继承动物类,不需要implements实现游泳类。

public class Rabbit extends Animal {
    public Rabbit() {
    }

    public Rabbit(String name, int age) {
        super(name, age);
    }

    public void eat(){
        System.out.println("兔子在吃胡萝卜");
    }
}

接下来是狗类,它继续要继承父类,有需要实现游泳类。

public class Dog extends Animal implements swim{
    public Dog() {
    }

    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("狗在吃骨头");
    }

    @Override
    public void swim() {
    System.out.println("狗在游泳");
    }
}

最后一个是青蛙类,跟狗类的相识

public class Frog extends Animal implements swim{

    public Frog() {
    }

    public Frog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("青蛙在吃虫子");
    }

    @Override
    public void swim() {
    System.out.println("青蛙在游泳");
    }
}

接下来我们在测试类中进行测试,创建对象

public class Test {
    public static void main(String[] args) {
        //创建对象
        Frog f = new Frog("小青",1);
        System.out.println(f.getName()+","+f.getAge());
        f.eat();
        f.swim();
    }
}

输出的结果为:

小青,1
青蛙在吃虫子
青蛙在游泳

接口中成员的特点

成员变量

只能是常量(不能发生改变的)

默认修饰符:public static final

final:不能改变

static:方便进行调用

public:公共的,在什么地方都可以使用接口里面的常量

构造方法

没有

成员方法

只能是抽象方法

默认修饰符:public abstract

JDK7以前:接口中只能定义抽象方法。

接口和类之间的关系

类和类的关系:

继承关系,只能单继承,不能多继承,但是可以多层继承。

类和接口的关系:

实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。在实现类当中实现了多个接口那么要把所有的抽象方法全部重写才可以。

如果多个接口中出现重名的抽象方法,那我们应该怎么办呢?

代码测试一下

我们先定义两个接口

public interface Inter1 {
    public abstract void method1();
    public abstract void method2();
    public abstract void method3();
}
public interface Inter2 {
    public abstract void method1();
    public abstract void method2();
    public abstract void method3();
    public abstract void method4();
}

在两个接口里有相同的抽象方法,现在我们定义个实现类

public class InterImpl implements Inter1,Inter2{
    @Override
    public void method1() {
        
    }

    @Override
    public void method2() {

    }

    @Override
    public void method3() {

    }

    @Override
    public void method4() {

    }
}

结果显而易见,我们只需要定义一次重复的抽象方法

接口和接口的关系:

继承关系,可以单继承,也可以多继承。

但是要注意,如果实现类实现了最下面的子接口,那么就需要重写所有的抽象方法

代码演示一下

接口1

public interface Inter1 {
    public abstract void method1();
}

接口2

public interface Inter2 {
    public abstract void method2();
}

接口3,继承接口1和接口2

public interface Inter3 extends Inter2,Inter1 {
    public abstract void method3();
}

实现类实现接口3

public class InterImpl implements Inter3{
    @Override
    public void method3() {
        
    }

    @Override
    public void method1() {

    }

    @Override
    public void method2() {

    }
}

需要把接口1,2,3的全部抽象方法重写一遍

JDK8新增方法

允许在接口中定义默认方法,需要使用关键字default修饰。

作用:解决接口升级问题

接口中默认方法的定义格式:

public default 返回值类型 方法名(参数列表){}

范例

public default void show(){}

接口默认方法的注意事项

  1. 默认方法不是抽象方法,所以不强制被重写,但是如果被重写,重写的时候去掉default关键字。
    代码演示
    创建一个接口,包含默认方法和抽象方法
public interface Inter {

    public abstract void method();

    public default void show(){
        System.out.println("接口中得默认方法---show");
    }
}

实现类,只需要重写抽象方法

public class InterImpl implements Inter {
    @Override
    public void method() {
        System.out.println("实现类重写得抽象方法");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        //创建实现类的对象
        InterImpl ii = new InterImpl();
        ii.method();
        ii.show();
    }
}

如果你想重写默认方法,就只需要写它的方法名,按回车,idea会自动书写,但此时重写的方法就不能包含default,不然会报错。
3. public可以省略,default不能省略
4. 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写

允许在接口中定义静态方法,需要static修饰。

接口中静态方法的定义格式:

public static 返回值类型 方法名(参数列表){}

范例

public static void show(){}

接口中静态方法的注意事项

  1. 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用。
  2. public可以省略,static不可省略(如果省略,Java会把它当作抽象方法)
    代码演示
    接口
public interface Inter {

    public abstract void method();

    public static void show(){
        System.out.println("接口中得静态方法");
    }
}

实现类

public class InterImpl implements Inter {
    @Override
    public void method() {
        System.out.println("InterImpl重写得抽象方法");
    }

    //不叫重写,只是刚好与接口中得静态方法重名而已
    public static void show(){
        System.out.println("InterImpl重写得抽象方法");
    }
}

测试类

public class Test {
    public static void main(String[] args) {

        //调用接口中得静态方法
        Inter.show();

        //调用实现类里面得静态方法
        InterImpl.show();

        //重写定义:子类把父类继承下来的虚方法表里面得方法进行覆盖了
        //一般静态,私有,最终的都不在虚方法表里
    }
}

JDK9新增方法

接口中私有方法的定义格式

格式1

private 返回值类型 方法名(参数列表){}

范例1

private void show()

格式2

private static 返回值类型 方法名(参数列表){}

范例2

private static void method(){}

接口的应用

  1. 接口代表规则,是行为的抽象,想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。
  2. 当一个方法的参数是接口,可以传递接口所有实现类的对象,这种方法称之为多态接口
    静态方法只能通过接口名调用,不能通过实现类名或者对象名调用。
  3. public可以省略,static不可省略(如果省略,Java会把它当作抽象方法)

适配器设计模式

设计模式是一套被反复使用,多数人知晓的经过分类编目的,代码设计经验的总结,使用设计模式是为了可重用代码,让代码更容易被人理解,保证代码可靠性,程序的重用性。

简单理解:设计模式就是各种套路

适配器设计模式:
解决接口与接口实现类之间的矛盾问题

  1. 当一个接口抽象方法过多,但是我要使用其中一部分的时候,就可以适配器设计模式
  2. 书写步骤:
    编写中间类xxxAdapter实现对应得接口,对接口中得抽象方法进行空实现,让真正得实现类继承中间类,并重写需要用得方法。
    为了避免其他类创建适配器类得对象,中间得适配器类用abstract进行修饰。

你可能感兴趣的:(认识接口和适配器设计模式)