欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-04 20:02:10
...

先来张图大致了解一下两者的区别:
接口和抽象类的区别(特别注意JDK8的接口可以有实现)

注:接口中只能有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修饰符不能省略。

相关标签: Java