接口时对行为的抽象,它是抽象方法的集合,利用接口可以达到API定义和实现分离的目的。
接口不能实例化;不能包含任何非常量成员,任何field 都是隐含的 public static final 的意义;
同时,没有非静态方实现,也就是说要么是抽象方法,要么是静态方法。Java标准类库中,定义了非常多的接口,比如 java.util.List 。
抽象类 是不能实例化的类,用abstract 关键字修饰class,其目的主要是代码重用。除了不能实例化,形式上和一般的java 类并没有太大区别,可以有一个或多个抽象方法,也可以没有抽象方法。 抽象类大多用于抽取相关Java类的公用方法实现或者是共同成员变量,然后通过继承的方式达到代码复用的目的。`,Java 标准库中,比如Collection框架,很多通用部分被抽取成为抽象类,例如 java.util.AbstractList 。
Java 类实现interface 使用 implements 关键词,继承 abstract class 则是使用extends 关键字,我们可以参考 Java 标准库中的ArrayList。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
在一些情况下存在特定场景,需要抽象出与具体实现、实例化无关的通用逻辑,或者纯调用关系的逻辑,但是使用传统的抽象类会陷入到单继承的窘境。以往常见的做法是,实现由
静态方法组成的工具类(Utils),比如java.util.Collections。
设想,为接口添加任何抽象方法,相应的所有实现了这个接口的类,也必须实现新增方法,否则会出现编译错误。对于抽象类,如果我们添加非抽象方法,其子类只会享受到能力扩展,而不用担心编译出问题。
接口的职责也不仅仅限于抽象方法的集合,其实有各种不同的实践。有一类没有任何方法的接口,通常叫作Marker Interface,顾名思义,它的目的就是为了声明某些东西,比如我
们熟知的Cloneable、Serializable等。这种用法,也存在于业界其他的Java产品代码中。
从表面看,这似乎和Annotation异曲同工,也确实如此,它的好处是简单直接。对于Annotation,因为可以指定参数和值,在表达能力上要更强大一些,所以更多人选择使
用Annotation。
Java 8增加了函数式编程的支持,所以又增加了一类定义,即所谓functional interface,简单说就是只有一个抽象方法的接口,通常建议使用@FunctionalInterface
Annotation来标记。Lambda表达式本身可以看作是一类functional interface,某种程度上这和面向对象可以算是两码事。我们熟知的Runnable、Callable之类,都
是functional interface,
还有一点可能让人感到意外,严格说,Java 8以后,接口也是可以有方法实现的!
从Java 8开始,interface增加了对default method
的支持。Java 9以后,甚至可以定义private default method
。Default method提供了一种二进制兼容的扩展已有接口的办法。比如,我们熟知的java.util.Collection,它是collection体系的root interface,在Java 8中添加了一系列default method,主要是增加Lambda、Stream相关的功能。