java面试分享-------接口和抽象类的含义和区别
先来看定义:
接口
是对行为的抽象,它是抽象方法的集合,利用接口可以达到API定义和实现分离的目的。接口,不能实例化;不能包含任何非常量成员,任何feld都是隐含着public static final的意义;同时,没有非静态方法实现,也就是说要么是抽象方法,要么是静态方法。
抽象类
是不能实例化的类,用abstract关键字修饰class,其目的主要是代码重用。除了不能实例化,形式上和一般的Java类并没有太大区别,可以有一个或者多个抽象方法,也可以没有抽象方法。抽象类大多用于抽取相关Java类的共用方法实现或者是共同成员变量,然后通过继承的方式达到代码复用的目的。
具体来说,接口就是 行为的抽象,就是你能做什么的抽象,而抽象类是你是由什么做的。
比如 ArrayList
,源码里面是这样的:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
其中,继承了一个抽象类和四个接口。
抽象类要怎么写呢?来看看 ArrayList
的继承的抽象类 AbstractList
:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
protected AbstractList() {
}
public boolean add(E e) {
add(size(), e);
return true;
}
abstract public E get(int index);
...
}
我们不难发现,抽象类中有 具体的方法实现、抽象函数等,
我们再来看看ArrayLis
t继承的接口List:
public interface List<E> extends Collection<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
可以看出,接口里面所有的方法都没有函数体(除了java8后来增加的 default 方法),再来看 ArrayList的源码:
public boolean add(E e) {
...
}
public E get(int index) {
...
}
public int size() {
...
}
public <T> T[] toArray(T[] a) {
...
}
我们很容易看见,ArrayList
实现了继承的抽象类和接口的方法,那么什么该实现什么不该实现呢?有下面的定义:
- 一个普通类(非接口)继承了抽象类时,必须要实现其所有抽象方法,而不一定要重写其非抽象方法。
- 一个接口继承了抽象类时,不用继承所有的抽象方法。
- 一个抽象类继承了另一个抽象类时,也不用继承所有的抽象方法。
- 一个普通类继承了接口时,必须重写其所有抽象方法。
- 一个接口继承了另一个接口时,不必继承其所有抽象方法。
- 一个抽象类继承了接口时,不必继承其所有抽象方法。
综上,我们给出了如下区别
相同点:
(1)都不能被实例化
(2)接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。
不同点:
(1)接口只有定义,不能有方法的实现,java 1.8中可以定义default方法体,而抽象类可以有定义与实现,方法可在抽象类中实现。
(2)实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但一个类只能继承一个抽象类。所以,使用接口可以间接地实现多重继承。
(3)接口强调特定功能的实现,而抽象类强调所属关系。
(4)接口成员变量默认为public static final,必须赋初值,不能被修改;其所有的成员方法都是public、abstract的。抽象类中成员变量默认default,可在子类中被重新定义,也可被重新赋值;抽象方法被abstract修饰,不能被private、static、synchronized和native等修饰,必须以分号结尾,不带花括号。
(5)接口被用于常用的功能,便于日后维护和添加删除,而抽象类更倾向于充当公共类的角色,不适用于日后重新对立面的代码修改。功能需要累积时用抽象类,不需要累积时用接口。
接口vs抽象类vs类
- 支持多重继承:接口支持;抽象类不支持;类不支持;
- 支持抽象函数:接口语义上支持;抽象类支持;类不支持;
- 允许函数实现:接口不允许;抽象类支持;类允许;
- 允许实例化:接口不允许;抽象类不允许;类允许;
- 允许部分函数实现:接口不允许;抽象类允许;类不允许。
- 定义的内容:接口中只能包括public函数以及public static fnal常量;抽象类与类均无任何限制。
- 使用时机:当想要支持多重继承,或是为了定义一种类型请使用接口;当打算提供带有部分实现的“模板”类,而将一些功能需要延迟实现请使用抽象类;当你打算提供完整的具体实现请使用类。