• Java 面向对象(六)接口


    一、接口

    •   接口Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(JDK 9)。
    •   接口的定义:它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。   
    •   接口的使用:它不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。

     Tips:引用数据类型:数组,类,接口等。

    二、定义格式

      语法格式:

    【权限修饰符】 interface 接口名称 {
       接口的成员列表如下: // 抽象方法 // 默认方法 // 静态方法 // 私有方法 }

      1、JDK1.7及以前接口成员有两种:静态常量和抽象方法(JDK7+)

        全局的静态的常量:接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰(可省略),其实就是接口中的【常量】。

        公共的抽象方法:使用publc abstract 关键字修饰,(可以省略)没有方法体。该方法供子类实现使用。

       语法格式

    public static final 数据类型 变量名 = 值;
    public abstract 返回值类型 方法名称(参数列表);

       Demo:

    1 public interface InterFaceName {
    2    public static final long MAX_SPEED = 7900000;  //常量
    3   public abstract void method();                 //抽象方法
    4 }

         Tips:一旦使用final关键字进行修饰,说明不可改变。

        注意事项

        a、接口当中的常量,可以省略 public static final注意:不写也照样是这样。

        b、接口当中的常量,必须进行赋值;不能不赋值

        c、接口中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)

      2、JDK1.8以后接口有增强两个成员:默认方法和静态方法(JDK8+)

        默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。

       语法格式

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

       静态方法:使用public static 修饰,不可省略,供接口直接调用。

       Demo:

    1 public interface InterFaceName {
    2     public default void method() {
    3         // 执行语句
    4     } 
    5     public static void method2() {
    6         // 执行语句
    7     }
    8 }

         扩展:

       (1)为什么 Java8 要允许接口中定义静态方法?

            因为JDK发展了一段时间后,发现类库中,多了很多的成组的API,如Array和Arrays类,Collection接口和Collections工具类。

         一般工具类都是静态方法,这些静态方法,基本上都是为前面这个对应接口服务的。当把这样的静态方法直接挪到接口中定义就好了,减少了这样的工具类的出现。

       (2)为什么 Java8 要允许接口中定义默认方法?

          因为有的时候,一个接口它的大多数实现类对接口的抽象方法的实现代码是一样的,那样写好几次就非常麻烦。即相当于,默认方法是原来的抽象方法有了一个默认实现。

          如果实现类的实现和接口一样,就不需要重写,如果不一样就重写即可。

      3、JDK1.9以后增加两个接口成员:私有方法和私有静态方法(JDK9+)

        私有方法:使用 private 修饰,供接口中的默认方法或者静态方法调用。

        Demo:

    1 public interface InterFaceName {
    2     private void method() {
    3         // 执行语句
    4     }
    5 }

    三、基本的实现

      1、实现的概述

        类与接口的关系为实现关系,即类实现接口,该类也可以称为接口的实现类,也可以称为接口的子类。

       实现的动作似继承,格式相仿,只是关键字不同,实现使用 implements 关键字。

       非抽象子类实现接口

      •  必须重写接口中所有的抽象方法。
      •    继承了接口的默认方法,即可以直接调用,也可以重写。

       实现格式

    class 类名 implements 接口名 {
        // 重写接口中抽象方法【必须】
        // 重写接口中默认方法【可选】
    }

      2、抽象方法的使用

          接口中的抽象方法必须全部实现。

          Demo:

     1 // 定义接口:
     2 public interface LiveAble {
     3     // 定义抽象方法
     4     public abstract void eat();
     5     public abstract void sleep();
     6 }
     7 
     8 // 定义实现类
     9 public class Animal implements LiveAble {
    10     @Override
    11     public void eat() {
    12         System.out.println("吃东西");
    13     } 
    14     @Override
    15     public void sleep() {
    16         System.out.println("晚上睡");
    17     }
    18 }
    View Code

      3、默认方法的使用

          可以继承,可以重写,二选一,但是只能通过实现类的对象来调用。

           (1)继承默认方法

          Demo:

     1 // 定义接口
     2 public interface LiveAble {
     3     public default void fly(){
     4         System.out.println("天上飞");
     5     }
     6 }
     7 
     8 // 定义实现类
     9 public class Animal implements LiveAble {
    10     // 继承,什么都不用写,直接调用
    11 }
    12 
    13 // 测试类
    14 public class InterfaceDemo {
    15     public static void main(String[] args) {
    16         // 创建子类对象
    17         Animal a = new Animal();
    18         // 调用默认方法
    19         a.fly();
    20     }
    21 }
    22 输出结果:
    23 天上飞
    View Code

        (2)重写默认方法

     1 // 定义接口
     2 public interface LiveAble {
     3     public default void fly(){
     4         System.out.println("天上飞");
     5     }
     6 }
     7 
     8 // 定义实现类
     9 public class Animal implements LiveAble {
    10     @Override
    11     public void fly() {
    12         System.out.println("自由自在的飞");
    13     }
    14 }
    15 
    16 // 定义测试类
    17 public class InterfaceDemo {
    18     public static void main(String[] args) {
    19         // 创建子类对象
    20         Animal a = new Animal();
    21         // 调用重写方法
    22         a.fly();
    23     }
    24 } 
    25 输出结果:
    26 自由自在的飞
    View Code

      4、静态方法的使用

          静态与 .class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用。

         语法格式

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

          Demo:

     1 // 定义接口
     2 public interface LiveAble {
     3     public static void run(){
     4         System.out.println("跑起来~~~");
     5     }
     6 }
     7 
     8 // 定义实现类
     9 public class Animal implements LiveAble {
    10     // 无法重写静态方法
    11 }
    12 
    13 // 定义测试类
    14 public class InterfaceDemo {
    15     public static void main(String[] args) {
    16     // Animal.run(); // 【错误】无法继承方法,也无法调用
    17     LiveAble.run(); //
    18     }
    19 } 
    20 输出结果:
    21 跑起来~~~
    View Code

      5、私有方法的使用

        •    私有方法:只有默认方法可以调用;
        •    私有静态方法:默认方法和静态方法可以调用;

         语法格式

    private 返回值类型 方法名称(参数列表){ 方法体}            普通私有方法
    private static 返回值类型 方法名称(参数列表) { 方法体}    静态私有方法

         如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法去调用。

         Demo:

     1 public interface LiveAble {
     2     default void func(){
     3         func1();
     4         func2();
     5     } 
     6     private void func1(){
     7         System.out.println("跑起来~~~");
     8     }
     9     private void func2(){
    10         System.out.println("跑起来~~~");
    11     }
    12 }
    View Code

    四、接口的多实现(冲突问题)

       在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。
       实现格式

    class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... {
        // 重写接口中抽象方法【必须】
        // 重写接口中默认方法【不重名时可选】
    }
    

      1、抽象方法

        接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次

        Demo:

     1 // 定义接口
     2 interface A {
     3     public abstract void showA();
     4     public abstract void show();
     5 } 
     6 interface B {
     7     public abstract void showB();
     8     public abstract void show();
     9 }
    10 
    11 //定义实现类
    12 public class C implements A,B{
    13     @Override
    14     public void showA() {
    15         System.out.println("showA");
    16     } 
    17     @Override
    18     public void showB() {
    19         System.out.println("showB");
    20     }
    21      @Override
    22      public void show() {
    23         System.out.println("show");
    24     }
    25 }
    View Code

      2、默认方法

        当一个类同时实现了两个甚至更多个接口时,这些个接口中出现了方法签名相同的默认方法时,

        必须在这个类中,做出选择:

          (1)保留其中一个,放弃另一个;

          (2)两者都不用,完全重写一个;

        Demo:

     1 interface A{
     2     public default  void test(){
     3         System.out.println("aaa");
     4     }
     5 }
     6 interface B{
     7     public default  void test(){
     8         System.out.println("bbb");
     9     }
    10 }
    11 class C implements A,B{ 
    12         //选择一:保留其中一个,放弃另一个
    13         A.super.test();  //保留A接口的实现
    14         B.super.test();  //保留B接口的实现  
    15 }
    16 
    17 class C1 implements A,B{ 
    18     //选择二:两者都不用,完全重写一个
    19     public void test(){
    20         System.out.println("ccc");
    21     }
    22 }

      3、静态方法

        接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。

      4、优先级的问题

        当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的方法签名一样的方法,怎么办?

        如何选择?

          (1)默认选择:编译器默认选择父类中的方法

          (2)改选保留接口的

          (3)完全自己重写

        Demo:

     1 class Father{
     2     public void test(){
     3         System.out.println("ffff");
     4     }
     5 }
     6 interface D{
     7     public default void test(){
     8         System.out.println("dddd");
     9     }
    10 }
    11 class Son1 extends Father implements D{
    12     //选择一:默认选择, 保留父类的
    13 }
    14 
    15 class Son2 extends Father implements D{
    16     //选择二:改选接口的
    17         public void test() {
    18             D.super.test();
    19         }
    20 }
    21 
    22 class Son3 extends Father implements D{
    23     // 完全自己重写
    24          public void test() {
    25               System.out.println("ssss");
    26         }
    27 }    

    五、接口的多继承

        一个接口能继承另一个或者多个接口,这和类之间的继承比较相似。接口的继承使用 extends 关键字,子接口继承父接口的方法。

       如果父接口中的默认方法有重名的,那么子接口需要重写一次。

       Demo:

     1 //定义父接口
     2 interface A {
     3     public default void method(){
     4         System.out.println("AAAAA");
     5     }
     6 } 
     7 interface B {
     8     public default void method(){
     9         System.out.println("BBBBB");
    10     }
    11 }
    12 
    13 // 定义子接口
    14 interface D extends A,B{
    15     @Override
    16     public default void method() {
    17         System.out.println("DDDDD");
    18     }
    19 }

      Tips:子接口重写默认方法时,default 关键字可以保留;子类重写默认方法时,default 关键字不可以保留。

    六、成员特点

    •   接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用 public static final 修饰。
    •       接口中,没有构造方法,不能创建对象。
    •       接口中,没有静态代码块。
    •       一个类如果直接继承父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。

     七、接口的特点

      1、接口是标准,就是用来被遵守的,即就是用来被实现的,那么要求实现类在实现接口时,必须实现/重写所有的抽象方法,否则这个实现类就得是一个抽象类;

      2、接口也是不能直接创建对象的;

      3、接口类型的变量与实现类的对象构成多态引用;

      4、一个类继承父类时,Java只支持单继承,但是一个类在实现接口时,可以同时实现多个接口;

      5、一个类如果同时继承父类,又实现接口时,要求继承在前,实现在后;

    【修饰符】 class 实现类  extends 父类  implements 父接口们{}

      6、在Java中,接口还可以继承接口;

    【权限修饰符】 interface 子接口  extends 父接口们{ }
    

      

  • 相关阅读:
    在Android工程中运行Java程序问题
    sklearn.neighbors.kneighbors_graph的简单属性介绍
    python中的“.T”操作
    numpy中关于*和dot的区别
    一个Window Service引发的感想
    项目管理之初步认识
    由敏捷开发中开发认领自己的工作内容的感想
    SQL Server2008 inner join多种方式的实践
    浅谈业务逻辑和技术哪个更重要
    敏捷人生之初步认识
  • 原文地址:https://www.cnblogs.com/niujifei/p/11369679.html
Copyright © 2020-2023  润新知