接口和抽象类的区别(特别注意JDK8的接口可以有实现)

标签: Java

先来张图大致了解一下两者的区别:
接口和抽象类的区别

注:接口中只能有static、final变量,不能有其他变量。表格中的一处错误:抽象类不能有default修饰符。

Java 8新特性–接口默认方法

默认方法是在接口中的方法签名前加上default关键字的实现方法。

/**
 * 简单例子
 */
interface InterfaceA {
    default void foo() {
        System.out.println("InterfaceA foo");
    }
}

class ClassA implements InterfaceA {
}

public class Test {
    public static void main(String[] args) {
        // 打印:“InterfaceA foo”
        new ClassA().foo(); 
    }
}

为什么要有默认方法?

在Java 8之前,接口与其实现类之间的耦合度过高(tightly coupled),当需要为一个接口添加方法时,所有的实现类都必须随之修改。默认方法可以为接口添加新的方法,而不会破坏已有的接口的实现。这在lambda表达式作为Java 8语言的重要特性出现之际,为升级旧接口且保持向后兼容(backward compatibility)提供了途径。

/**
 * Iterable接口中的forEach默认方法
 */
public interface Iterable<T> {
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
}

默认方法的继承

接口默认方法的继承分三种情况(分别对应下面的InterfaceB接口、InterfaceC接口和InterfaceD接口):

  1. 不覆写默认方法,直接从父接口中获取方法的默认实现。
  2. 覆写默认方法,这跟类与类之间的覆写规则相类似。
  3. 覆写默认方法并将它重新声明为抽象方法,这样新接口的子类必须再次覆写并实现这个抽象方法。
interface InterfaceA {
    default void foo() {
        System.out.println("InterfaceA foo");
    }
}

interface InterfaceB extends InterfaceA {
}

interface InterfaceC extends InterfaceA {
    @Override
    default void foo() {
        System.out.println("InterfaceC foo");
    }
}

interface InterfaceD extends InterfaceA {
    @Override
    void foo();
}

public class Test {
    public static void main(String[] args) {
        // 打印:“InterfaceA foo”
        new InterfaceB() {}.foo();
        // 打印:“InterfaceC foo”
        new InterfaceC() {}.foo();
        new InterfaceD() {
            @Override
            public void foo() {
                // 打印:“InterfaceD foo”
                System.out.println("InterfaceD foo");
            }
        }.foo();
        
        // 或者使用lambda表达式
        ((InterfaceD) () -> System.out.println("InterfaceD foo")).foo();
    }
}

Java 8新特性–接口静态方法

interface InterfaceA {
    default void foo() {
        printHelloWorld();
    }
    
    static void printHelloWorld() {
        System.out.println("hello, world");
    }
}

public class Test {
    public static void main(String[] args) {
        // 打印:“hello, world”
        InterfaceA.printHelloWorld();
    }
}

总结及注意点:default关键字只能在接口中使用(以及用在 switch语句的default分支),不能用在抽象类中;接口默认方法不能覆写Object类的equals、hashCode和toString方法;接口中的静态方法必须是public的,public修饰符可以省略,static修饰符不能省略。

版权声明:本文为weixin_36759405原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_36759405/article/details/82774558