当前位置: 移动技术网 > IT编程>软件设计>设计模式 > 接口

接口

2020年07月16日  | 移动技术网IT编程  | 我要评论

接口(interface)

接口的基础语法:

接口介绍:

  1. 接口也是一种引用数据类型 。编译之后也是一个class字节码文件。

  2. 接口是完全抽象的。(抽象类是半抽象) 或者也可以说接口是特殊的抽象类。

  3. 接口怎么定义的,语法是什么?

    [修饰符列表] interface 接口名{}

  4. 接口支持多继承,一个接口可以继承多个接口。

  5. 一般情况下接口只包含两部分内容。一部分是:常量,一部分是:抽象方法

  6. 一般情况下接口中的所有元素都是public修饰的。(都是公开的。)

  7. 接口中的抽象方法定义时:public abstract修饰符可以省略。

  8. 接口中定义常量时:public static final 可以省略。

  9. 一般情况下接口中的方法都是抽象方法,所有接口中的方法不能有方法体。

代码演示:

public class Test01{
    public static void main(String[]args){
        //访问接口的常量
        System.out.println(MyMath.PI);
        
        //错误: 无法为最终变量PI分配值
        //MyMath.PI=3.1415928;
        
    }
}

//我的数学接口
interface MyMath{
    //常量
    // public static final double PI=3.1415926;
    //接口中public static final 可以省略 如:
    double PI=3.1415926;
    //再如:
    int k=100; //接口中随便写一个变量就是常量:值不能发生改变的变量。
//抽象方法
//接口中既然都是抽象方法,那么public abstract在编写时可以省略
//public abstract int sum(int a,int b);
    int sum(int a,int b);
 
// 接口抽象方法不能带有主体
//    void dosome(){}  错误
    
//相减的抽象方法
    int sub(int a,int b);
}

接口多继承:

  1. 类与类之间是单继承。之间父类只有一个。
  2. 类与接口之间是多实现,一个类可以实现多个接口。
  3. 接口与接口之间是多继承
  4. 注意:
    1. 多个父接口中的抽象方法如果重复,没有关系
    2. 多个父接口中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,而且要带着default关键字
//定义接口
interface A{
    public abstract void methodA();
    public abstract void methodCommon(); 
      public default void methodDefault(){
        System.out.println("接口A默认方法");
    }
}

//定义接口
interface B{
 public abstract void methodB();
 public abstract void methodCommon();  
      public default void methodDefault(){
        System.out.println("接口B默认方法");
    }
}

//定义接口  接口可继承接口 支持多继承
//这个接口中有4个方法
/*
methodA():来自于接口A
methodB():来自于接口B
methodCommon():同时来自于接口A,B
methodA():来自于自己
*/
interface C extends A,B{
    public abstract void method();
  //重写重复的默认方法
     @Override
    default void methodDefault() {

    }
}

接口实现(implements):

  1. 类和类之间叫做继承,类和接口之间叫做实现。(仍然可以将实现看做’继承’)

    ​ 继承关键字:extends。

    ​ 实现关键字:implements

  2. 当一个非抽象的类实现接口的话,必须重写接口中所有的抽象方法。重写后方法的修饰符必须为public,若方法名重复,重写一次即可。

  3. 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类必须是一个抽象类。

  4. 一个类可以同时实现多个接口。java中的接口弥补了单继承带来的缺陷

  5. 当运用多态创建对象,调用其他接口可能会出现的问题:

    1. 如下(类实现多接口演示中),接口K和M虽然没有继承关系,但编写代码的时候,可以互转。编译器没意见,但是运行时可能出现ClassCastException异常。

    2. 之前有一个结论:

      无论向上转型还是向下转型,两种类型之间必须要有继承关系,没有继承关系,编译器会报错。(但这句话不适用在接口方面)。但实际上和之前还是一样,需要:if+instanceof运算符进行判断

代码演示:

public class Test02{
public static void main(String[]args){
    //使用多态
    MyMath m=new MyMathImpl();
    System.out.println( m.sum(10,9));
    System.out.println( m.sub(10,9));
    
}
}
//数学接口
interface MyMath{
    double PI=3.1415926;
    //求和方法
    int sum(int a,int b);
    //相减方法
    int sub(int a,int b);
    
}

//实现数学接口的类
class MyMathImpl implements MyMath{
    //错误:正在尝试分配更低的访问权限:以前为public
    /*
        int sum(int a,int b){
        return a+b;
    };
    */
    
    //重写接口中方法
     //求和方法
   public int sum(int a,int b){
        return a+b;
    };
    //相减方法
   public int sub(int a,int b){
        return a-b;
    };
}

类实现多接口演示:

//接口与接口支持多继承
/*
interface X{}
interface Y{}
interface Z extends X,Y{}
*/

//-----------------------------------------------------
//类实现多接口
public class Test03{
    public static void main(String[]args){
        //多态使用
        A a=new D();
        B b=new D();
        C c=new D();
        //不能直接去调用其他接口方法
       // a.m2();
        
        //这个编译没问题 运行也没问题
        B b2=(B)a;
        b2.m2();
        
       // M m=new E();
        //经过测试:接口和接口之间在进行强制类型转化的时候,没有继承关系,也可以强转。
        //但一定要注意:运行时可能会出现ClassCastException(类型转化)异常。
        //要先用instanceof 判断
        
       //if(m instanceof K){ K k=(K)m;}
        
        
    }
}
//-----------------------------------------------------
interface K(){}
interface M(){}
class E implements M{
    
}

//-----------------------------------------------------


interface A{
    void m1();
}

interface B{
    void m2();
}
interface C{
    void m3();
}

//实现多个接口,其实就类似于多继承
class D implements A,B,C{
   //重写全部接口的方法,若方法名重复,只需要重写一次即可
    public void m1(){
        System.out.println("m1");
    };
    public void m2(){
        System.out.println("m2");
    };
    public void m3(){};
}

接口的默认方法定义:

  1. java8开始接口允许定义默认方法

  2. 格式:(public可省略)
    public default 返回值类型 方法名称(参数列表){方法体}

  3. 备注:接口中默认方法可以解决接口升级问题

    如:

    当一些类实现接口后,若接口中新增抽象方法,这些实现类必须得去重写接口中的新增方法,从而导致项目中代码需整体改动,可能引发错误。

  4. 接口的默认方法:可以通过接口实现类对象,直接调用

  5. 接口的默认方法:也可以被接口实现类进行覆盖重写如果实现类实现多个接口中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。

代码演示:

//测试类
class Test {
    public static void main(String[] args) {
        //多态 向上转型
        MyInterfaceDefault m=new MyInterfaceDefaultA();
        MyInterfaceDefaultB m1=new MyInterfaceDefaultB();
        //调用MyInterfaceDefaultA中methodAbs方法
        m.methodAbs();//MyInterfaceDefaultA
        //可从接口里直接调用
        m.methodDefault;//新添加的默认方法
        System.out.println("==============");
        m1.methodAbs(); //MyInterfaceDefaultB
        //调用重写的methodDefault方法
        m1.methodDefault();//实现类B覆盖重写了接口的默认方法
    }
}

public interface MyInterfaceDefault {
   //抽象方法
    public abstract void methodAbs();

    //新添加了一个抽象方法 MyInterfaceDefaultA和MyInTerfaceDefaultB去重写该方法
   // public abstract  void methodAbs1();

    //新添加的方法,改成默认方法
    public default void methodDefault(){
        System.out.println("新添加的默认方法");
    }

}

class MyInterfaceDefaultA implements MyInterfaceDefault{

    @Override
    public void methodAbs() {
        System.out.println("MyInterfaceDefaultA");
    }
}


class MyInterfaceDefaultB implements MyInterfaceDefault{


    @Override
    public void methodAbs() {
        System.out.println("MyInterfaceDefaultB");
    }

    @Override
    public void methodDefault() {
        System.out.println("实现类B覆盖重写了接口的默认方法");
    }
}

接口的静态方法定义:

  1. 从java8开始 接口中允许定义静态方法。

  2. 格式:
    public static 返回值类型 方法名称(参数列表){
    方法体;
    }
    提示:就是将abstract或者default换成static即可,带上方法体

  3. 注意:不能通过接口实现类的对象调用接口中的静态方法

  4. 正确写法:通过接口名称,直接调用其中的静态方法
    接口名称.静态方法名(参数)

代码演示:

//测试类
class Test02{
    public static void main(String[] args) {
        //创建实现类对象
        MyInterfaceStaticImpl m=new MyInterfaceStaticImpl();

        //错误写法
        //不能通过接口实现类的对象调用接口中的静态方法
       // m.methodStatic();
        
        //直接用接口调用
        MyInterfaceStatic.methodStatic//输出:这是接口的静态方法!
    }
}

//接口
public interface MyInterfaceStatic {
    public static void methodStatic(){
        System.out.println("这是接口的静态方法!");
    }
}

//实现类
class MyInterfaceStaticImpl implements MyInterfaceStatic{


}

接口的私有方法定义:

  1. 使用场景:当编写接口的默认或静态方式时,可能会出现一些重复代码,为了使代码简洁,我们需要抽取一个公有方法,用来解决两个默认方法之间重复代码的问题,但是这个共有方法不应该让实现类使用,应该私有化的

  2. 解决方案:
    java9开始,接口中允许定义私有方法

    1. 普通私有方法:解决多个默认方法之间重复代码问题
      格式:
      private 返回值类型 方法名称(参数列表){
      方法体;
      }
    2. .静态私有方法:解决多个静态方法之间重复代码问题
      格式:
      private static 返回值类型 方法名称(参数列表){
      方法体;
      }

代码演示(普通私有方法):

//测试类
class Test03{
    public static void main(String[] args) {
        //多态
        MyInterfacePrivateA m=new MyInterfacePrivateAImpl();
        m.methodDefault1();
        MyInterfacePrivateAImpl m1=new MyInterfacePrivateAImpl();
        m1.methodDefault2();
    }
}

//接口
public interface MyInterfacePrivateA {
    public default void methodDefault1(){
        System.out.println("这是一个默认方法1");
        //直接调用methodCommon()
      methodCommon();
    }
    public default void methodDefault2(){
        System.out.println("这是一个默认方法2");
        //直接调用methodCommon()
       methodCommon();
    }

    //私有的公有方法
    private void methodCommon(){
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }
}

//实现类
class MyInterfacePrivateAImpl implements MyInterfacePrivateA{
    public void methAnother(){
        //若接口的共有方法不是private,可直间访问到接口中的默认方法
        //methodCommon();
    }
}

代码演示(静态私有方法):

//测试类
class Test04{
    public static void main(String[] args) {
        MyInterfacePrivateB m=new MyInterfacePrivateAImplB();
        //不能通过接口实现类的对象调用接口中的静态方法
        //m.methodDefault1();
        //直接用接口调用
        MyInterfacePrivateB.methodDefault1();
        MyInterfacePrivateB.methodDefault2();

    }
}

//接口
public interface MyInterfacePrivateB {
    public static void methodDefault1(){
        System.out.println("这是一个静态方法1");
      methodCommon();
    }
    public static void methodDefault2(){
        System.out.println("这是一个静态方法2");
       methodCommon();
    }

    private static void methodCommon(){
        System.out.println("AAA");
        System.out.println("BBB");
        System.out.println("CCC");
    }
}

//实现类
class MyInterfacePrivateAImplB implements MyInterfacePrivateB{
    public void methAnother(){
        //若接口的共有方法不是private,可直间访问到接口中的默认方法
        //MyInterfacePrivateB.methodCommon();


    }
}

继承和实现同时存在:

  1. extends 关键字在前,implements 关键字在后
  2. 一个类如果直接父类当中的方法,和接口中的默认方法产生冲突时,优先用父类中的方法

代码演示

//测试类
class Test05{
    public static void main(String[] args) {

        Son s=new Son();
        s.method();//输出:父类的方法
    }
}

//父类
public class Fu {
    public void method(){
        System.out.println("父类方法");
    }
}

//接口
interface Inf{
    //默认方法
    public default void method(){
        System.out.println("接口方法");
    }
}

//子类
class Son extends Fu implements Inf{

}

接口在开发中的作用:

  1. 接口在开发中的作用,类似于多态在开发中的作用。

  2. 多态:面向抽象编程,不要面向具体编程。降低程序的耦合度,提高程序的扩展力。

    如:

    public class Master{
        public void feed(Dog d){};
        public void feed(Cat x){};
    }
    //假设又要养其他宠物,那么这时候需要再加1个方法。(修改代码)
    //这样扩展力太差了,违背了OCP原则(对扩展开放,对修改关闭)
    

    改为:

    public class Master{
        public void feed(Animal a){};
    
    }
    //面向Animal父类编程,父类比子类更抽象的,这样程序扩展力就更强
    
  3. 面向接口编程,可以降低程序的耦合度,提高程序的扩展力,符合OCP开发原则。

  4. 接口的使用离不开多态机制。(接口+多态才可以达到降低耦合度)。

  5. 任何接口都有调用者和实现者。接口可以将调用者和实现者解耦。

    调用者面向接口调用。

    实现者面向接口编写实现。

代码演示(抽象思维)

顾客点餐:

// 菜单 接口
public interface FoodMenu{
    //西红柿炒蛋
    void shizichaojidan();
    
   //鱼香肉丝
    void yuxiangrousi();
}


//  中国厨师  实现者
public class ChinaCooker implements FoodMenu{
    public void shizichaojidan(){
        System.out.println("中国厨师做了一个西红柿炒鸡蛋")
    }
    
    public void yuxiangrousi(){
        System.out.println("中国厨师做了一个鱼香肉丝")
    }
}

//  美国厨师  实现者
public class AmericCooker implements FoodMenu{
    public void shizichaojidan(){
        System.out.println("美国厨师做了一个西红柿炒鸡蛋")
    }
    
    public void yuxiangrousi(){
        System.out.println("美国厨师做了一个鱼香肉丝")
    }
}

// 消费者 调用者
public class Customer{
    //面向接口编程
    private FoodMenu foodMenu;
    //有参构造
    public Customer(FoodMenu foodMenu){
        this.foodMenu=foodMenu;
    }
    //无参构造
    public Customer(){
        
    }
    //get 方法
    public FoodMenu getFoodMenu(){
        return foodMenu;
    }
    //set 方法
    public void setFoodMenu(FoodMenu foodMenu){
        this.foodMenu=foodMenu;
    }
    
    //提供一个点餐方法
    public void order(){
        //用get方法调用
       // FoodMenu fm=this.getFoodMenu();
       // fm.shizichaojidan();
        //fm.yuxiangrousi();
        foodMenu.shizichaojidan();
        foodMenu.yuxiangrousi();
        //实现一个静态代理
        System.out.println("点餐结束");
    }
        
}

//测试类
public class Test06{
    public static void main(String[]args){
        //创建厨师对象
        FoodMenu cooker1=new ChinaCooker();
        //创建顾客对象
        Customer customer=new Customer(cooker1);
        //顾客点餐
        customer.order();//输出:中国厨师做了一个西红柿炒蛋
                         //     中国厨师做了一个鱼香肉丝
                         //     点餐结束
    }
}

本文地址:https://blog.csdn.net/MTCya/article/details/107346760

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网