抽象类和接口的区别(面试题)

210 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

在分析接口和抽象类的区别的时候我们可以先说一下他们的实现,抽象类是在类名前用abstract修饰extends继承,接口是用interface来修饰用implement来继承,然后抽象类只能单一继承,接口可以多继承中间用逗号分隔.

接口(interface)可以说成是抽象类的一种特例,接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final.

相同点:都不能实例化对象。

抽象类: 可以有构造方法,可以有普通成员变量,可以包含非抽象的普通方法,访问类型可以是public,protected,不能包含默认方法,

接口中: 不能有构造方法,没有普通成员变量,不能有非抽象的普通方法,接口中的抽象方法只能是public类型的,并且默认即为public abstract类型,Java 7接口可以包含:常量、抽象方法;Java 8额外包含:默认方法、静态方法;Java 9私有方法.

抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型.

在设计层面:接口的设计目的,是对类的行为进行约束,常用在框架的设计上,抽象类的实现目的,是代码复用,可以让这些类都派生于一个抽象类,在这个抽象类中实现了共有的方法,避免让所有的子类来实现这个共有的方法,这就达到了代码复用的目的.

面试官一定是想让我们讲讲JDK1.8对接口的

JDK8中对接口规范进行了新的定义,允许在接口中定义默认方法(使用default关键字修饰),静态方法,同时还推出了函数式接口(使用@FunctionInterface注解描述)设计.

应用场景:基于JDK8中接口新规范的定义,不仅可以扩展接口新功能(新的标准),还能保持接口向前兼容的特性。例如Java API中的集合操作规范.

JDK8中为了对接口业务进行扩展,但又不影响实现类,提供了默认方法.此类型的方法使用default关键字修饰,可以有方法体的实现.例如:

interface IA{
        default void doMethod01() {
                System.out.println("doMethod01");
        }
        default void doMethod02() {
                System.out.println("doMethod02");
        }
} 

接口默认方法提高了编程的灵活度,一个类在实现接口时,接口中假如有默认方法,默认方法可以有选择性的对其进行重写,但不是必须要重写.

接口默认方法,解决了java8和以前接口版本特性的兼容性问题,对于我们以后的程序开发,可以在接口子类中直接使用接口默认方法,而并不再需要在各个子类中都去实现这些方法了.

Java8中的接口规范,不仅允许定义多个默认方法,也允许在接口中定义多个静态方法,这些静态方法类似于 class 中的静态方法,可以通过接口名进行直接调用.

interface IB{
        static void doMethod() {
                System.out.println("doMethod()");
        }
}

接口中静态方法并不能在实现类中被覆写,实现类中可以声明相同的方法,但这两个方法之间除了名字相同,并没有 override 关系.

函数式接口:

Java8引入了一个是函数式接口(Functional Interfaces),此接口使用@FunctionalInterface修饰,并且此接口内部只能包含一个抽象方法.

@FunctionalInterface
public interface Comparator<T> {
   int compare(T o1, T o2);  // public abstract
}

说明:函数式接口推出的目的主要是为了配合 Lambda表达式的应用.

在JDK中的java.util.function包中定义了大量函数式接口。常用的有如下几个:

消费型接口(特点:方法有入参,没有返回值)

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
    ...
}

函数式接口(特点:方法有入参,有返回值)

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
    ...
}

判定式接口(特点:方法有入参,返回值为boolean)

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
    ...
}
 

供给式接口(特点:方法没有入参,但有返回值)

@FunctionalInterface
public interface Supplier<T> {
    T get();
    ...
}

说明:这些接口可以配合Lambda使用以减少我们自己接口的定义.