【JAVA基础】JAVA8中 抽象类和接口的异同

本文探讨了JAVA8中抽象类和接口的区别与联系。抽象类用于表示通用性,部分或全部方法可为抽象,不可实例化。接口则描述了类的一组需求,Java8新增了静态和默认方法。接口中的默认方法遵循“类优先”原则,一个类可实现多个接口,但遇到接口冲突需在实现类中解决。抽象类与接口的相似之处在于不能实例化,且两者均可在Java8后包含方法实现。主要区别在于继承方式(单继承 vs 多实现)、设计理念(所属关系 vs 功能实现)以及成员变量的默认特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 抽象类

什么是抽象类:

Java语言中,可以通过把类或者类中的某些方法声明为 abstract 来表示一个类是抽象类。抽象类跟普通类区别不大,唯一的区别就是抽象类中可以包含抽象方法,且抽象类不可以被实例化

那我们为什么要使用抽象类呢?

这里我个人觉得,在自下而上的类的继承层次结构中上移,位于上层的类更具有通用性,甚至有可能,在高层中的一些基类,有一些方法是不用实现的,具有抽象性的。例如:
一个最高的基类是动物,里面可能有各种方法(动作),例如:吃、行动、睡觉,对于动物这个最高的基类,这些方法都不需要实现,让它的子类去实现就好,就相当于这些方法都是抽象的,意味着将实现交给了子类。而对于子类,例如有一个子类羊,它向下还有更多的子类,例如:a类羊、b类羊、等等,对于羊这个类,对于行动这个方法,不同的子类羊行动的方式不同,因此这里依旧不需要实现,所以依旧这些方法可以定义为抽象的。
因此,在上面这个例子中,可以看出抽象类的使用场景:一个类有部分or全部的方法是不需要实现的(交付给子类实现),这样子的类为抽象类

扩展抽象类的方式

其实从上面的例子中,我们不难总结出扩展抽象类的两种选择:

  • 在子类中保留部分的抽象方法,这样子子类也要定义为抽象类
  • 在子类中实现全部的抽象方法,这样子子类就可以不定义为抽象类

几个不能和 abstract 共存的关键字

  1. final:被 final 修饰的类不能有子类(不能被继承)。而被 abstract 修饰的类一定是一个父类(一定要被继承),因此矛盾,无法共存
  2. private:抽象类中的私有的抽象方法,不被子类所知,就无法被复写。而抽象方法是一定要在子类中被实现的,因此矛盾,无法共存
  3. static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了,可是抽象方法运行没意义

关于抽象类的几个注意点

  1. 即使类中没有抽象方法,也可以将类定义为抽象类
  2. 抽象类不可以被实例化
  3. 抽象方法和抽象类都必须被 abstract 关键字修饰

2. 接口

什么是接口

接口是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。

Java8 对接口的变动有什么

主要变动的地方有两个:

  • 第一,在接口中增加了静态方法,可以直接在接口处申明静态方法并实现,调用方法同普通类的静态方法,举例:
// 在接口中写上静态方法
public interface MyInterface {
    public static void test() {
        System.out.println("实现静态方法");
    }
}

// 在其他类中调用
public class Main {
    public static void main(String[] args) {
        MyInterface.test();
    }
}

调用结果:
在这里插入图片描述

  • 第二,Java8 中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,使用 default 关键字修饰
// 在接口中实现默认方法
public interface MyInterface {
    default void testDefault() {
        System.out.println("实现默认方法");
    }
}

// 在实现类中调用方法
public class Main implements MyInterface{
    public static void main(String[] args) {
        Main m = new Main();
        m.testDefault();
    }
}

执行结果:
在这里插入图片描述
但在接口中可以写实现类的话,就会引发两个问题:

  • 第一,如果类A实现两个接口,两个接口各自实现了一个相同的方法,我在类A中调用该方法,是调用哪个接口的默认方法呢?
  • 第二,如果类A实现的一个接口中的默认方法,跟类A继承的类中的一个方法相同,我调用的是基类的方法,还是接口的默认方法呢?

关于这两个问题,有一个原则:默认方法的“类优先”原则
什么意思呢?就是:若一个接口中定义了一个默认方法,而另外一个父类或接口又定义了一个同名的方法时:

  • 选择父类中的方法,如果一个父类中提供了具体的实现,那么接口具有相同名称和参数的默认方法会被忽略
  • 接口冲突。如果实现的两个接口都提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么在实现类中必须覆盖方法来解决冲突

具体例子:
① 父类接口冲突

// 父类
public class Father {
    public void sayHello() {
        System.out.println("hello, this is Father");
    }
}

// 接口
public interface MyInterface {
    default void sayHello() {
        System.out.println("hello, this is MyInterface");
    }
}

// 子类
public class Main extends Father implements MyInterface{
    public static void main(String[] args) {
        Main m = new Main();
        m.sayHello();
    }
}

执行的结果:父类中的实现
在这里插入图片描述
② 两个接口冲突

// 接口1:
public interface MyInterface {
    default void sayHello() {
        System.out.println("hello, this is MyInterface");
    }
}

// 接口2:
public interface MyInterface1 {
    default void sayHello() {
        System.out.println("hello, this is MyInterface1");
    }
}

当类A同时实现这两个接口时,会发现提示:
在这里插入图片描述
因此,我们需要在类A中覆盖该方法,才能使程序正常运行

3. 抽象类和接口的相同点

  • 都不能被实例化
  • 接口的实现类或抽象类的子类,都只有在实现了接口或抽象类中的方法后,才能被实例化
  • 从 Java8 开始,抽象类和接口都可以有方法的实现(Java8 之前接口只有定义)

4. 抽象类和接口的不同点

  • 接口需要实现(implements),且一个类可以实现多个接口,抽象类需要被继承(extends),且只能单继承,即一个类只有一个父类
  • 接口的设计理念是 “has - a” ,关系,即强调特定功能的实现,而抽象类强调所属关系,即 “is - a” 关系
  • 接口中定义的成员变量默认为 public static final,不能被修改且需要赋初始值。而抽象类的成员变量跟普通类的相同
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值