• 接口和抽象类的区别(不讲废话,干货满满,JDK1.8最新整理)


    接口和抽象类的区别(不讲废话,干货满满,JDK1.8最新整理)

    1、抽象类

    以下说辞可能不太准确,但是会让你醍醐灌顶

    抽象类是把一些具有共同属性(包括行为)的东西抽象出来,比如:

    • 小狗有身高,体重,颜色,会叫,会跑
    • 小猫有身高,体重,颜色,会叫,会跑

    这个时候我们发现小猫和小狗都有共同的属性(包括行为:会叫,会跑),所以我们抽象一个动物类出来:

    public abstract class Animal {
      float weight;
      float height;
      String color;
    
      abstract void run();
    
      abstract void bark();
    
      void scratch() {
        System.out.println("animal can scratch");
      }
    }
    

    从这里我们可以得出结论1抽象类中可以有抽象方法普通方法

    我们再定义一个 Cat 类:

    image-20220321134411901

    编译器报错,说我们要么把 Cat 声明为抽象类,要么就实现 Animal 中的抽象方法

    这里我们可以得出结论2:如果子类继承了抽象类,就必须实现抽象类中的抽象方法

    有同学发现,既然抽象类不能实例化,那抽象类中的普通的方法有什么意义?

    意义就在于提高代码的可用性!什么是可用性,比如我上面的例子,动物会 scratch(挠人),我默认了所有的动物都是这样挠人的,就不需要子类再去挨个实现挠人的动作。

    2、接口

    抽象类很强大,它可以把属性和行为都抽象出来,但是存在一个很大的问题:耦合度过高

    举个栗子:我现在有个小鸟类,有个飞机类,如果需要我们抽象出来,我们应该怎么去抽?

    假设我们抽象出一个飞行类,里面只有一个抽象方法:abstract void fly()

    这时候小鸟能继承飞行类吗,继承了飞行类还能继承动物类吗?显然不能,这就体现出了抽象类的局限性。

    这时候,接口就出现了,接口就是为了抽象出行为,在 Java 中,只有单继承,但是有多实现。

    我们可以抽象出一个会飞的的接口:

    public interface Flyable {
      void fly();
    }
    

    如果是会游泳的动物,那我们再抽象出一个游泳的接口:

    public interface Swimmable {
      void swim();
    }
    

    现在小鸟可以继承动物类实现会飞的接口,飞机也可以实现会飞的接口

    青蛙可以继承动物类实现会游泳的接口某运动员也可以实现会游泳的接口

    这里我们可以得出结论3抽象类是对具有共同属性行为的事物进行抽象,接口只是对行为进行抽象。

    3、接口中的方法

    接口中默认的方法都是抽象的,我们先写一个小鸟类:

    image-20220321141349538

    编译器报错,告诉我们必须实现接口中的方法

    这里我们可以得出结论4:接口中的方法默认都是抽象的,子类必须实现所有的抽象方法。

    jdk1.8 新增了 default 方法和 static 方法,我们来看一下:

    default 方法:

    public interface Flyable {
      void fly();
    
      default void test() {
        System.out.println("测试 default 方法");
      }
    
    }
    

    写完后,编译器没有报错,说明子类不需要强制实现这个方法,但是接口也不能实例化,default方法存在的意义在哪儿呢?这个问题是不是似曾相识?

    对,是不是就是和抽象类中的普通方法一样,提高代码的可用性。

    这里可以得出结论5:接口中的default方法不需要子类实现

    static方法:

    public interface Flyable {
      void fly();
    
      default void test() {
        System.out.println("测试 default 方法");
      }
    
      static void test2() {
        System.out.println("测试 static 方法");
      }
    
    }
    

    子类没有报错,静态方法通过接口名直接调用:Flyable.test2()

    这里可以得出结论6:接口中的static方法也不需要子类实现,且通过接口名直接调用

    接口中还允许静态的字段,默认是public static final的,子类只能使用,不能修改

    总结

    结合结论1~6,我们可以得出接口和抽象类的区别:

    1. 抽象类是对具有共同属性行为的事物进行抽象,接口只是对行为进行抽象。
    2. 抽象类中可以有抽象方法和普通方法。
    3. 如果子类继承了抽象类,就必须实现抽象类中的抽象方法
    4. 接口中的方法默认都是抽象的,子类必须实现所有的抽象方法
    5. 接口中的 default 方法和 static 不需要子类实现。

    以上表述可能不太准确,且是基于JDK1.8做的demo,希望同学自己实现一下,加深印象,加深理解。

  • 相关阅读:
    spring-boot 速成(6) 整合disconf
    spring-boot 速成(5) profile区分环境
    dubbox REST服务使用fastjson替换jackson
    resteasy经验谈
    spring-boot 速成(4) 自定义配置
    spring-boot 速成(3) actuator
    idea 高级调试技巧
    spring-boot 速成(2) devtools之热部署及LiveReload
    bash编程之xargs实用技巧
    spring-boot 速成(1) helloworld
  • 原文地址:https://www.cnblogs.com/Fzeng/p/16036897.html
Copyright © 2020-2023  润新知