【翻译】Java接口与抽象类的区别
原文地址:Difference Between Interface vs. Abstract Class
一、理解抽象类
简单地来说,抽象类就是一个用abstract
关键字修饰的类,它可以包含任意多个抽象方法,不需要完整定义其行为。抽象类有一个强制的要求:不能创建其实例。
当我们被如何创建一个不能被实例化的类困扰时,抽象类就是解决问题的关键。让我们来看一个抽象类的基本结构:
public abstract class TestAbstractClass {
public abstract void abstractMethod();
public void normalMethod(){
//do something here...
}
}
上述类TestAbstractClass
拥有两个方法,一个是抽象方法,另一个是普通方法。如果一类中拥有一个抽象方法,那个这个类必须要声明成为抽象类。抽象方法指的是没有具体实现的方法。抽象方法会让破坏类的完整性,所以编译器会强迫将整个类声明为抽象的。
在应用中使用抽象类的唯一方法就是继承这个类。如果抽象类的子类没有再次被声明为抽象类,那么子类就可以被实例化。抽象类的子类同样继承超类的所有行为,超类同样可以持有子类的引用。
二、理解接口
接口是Java API中另一种基本形式,在集合、I/O或SWT中,接口随处可见。接口定义了交互的方式,是一种约定,所有实现该接口类都必须要遵守。这个约定本质上是一系列未实现的方法。Java中另一个用于未实现方法的关键字是abstract
。在Java中,类可以实现任意的接口,所以接口中所声明的方法都必须是public
。让我们来看看Java中接口定义的形式:
public interface TestInterface {
void implementMe();
}
上述接口的任意一个实现类都需要重写方法implementMe()
。只有一种场景下实现一个接口且不需要重写接口中的方法,即,当我们将接口的实现类声明为abstract
。示例如下:
public abstract class TestImplement implements TestInterface {
//No need to override implementMe
}
除此之外,我们都将必须在接口实现类中重写方法“implementMe()··。
public class TestImplement implements TestInterface {
@Override
public void implementMe() {
// TODO Auto-generated method stub
}
}
三、接口与抽象类之间的区别
让我们快速回顾一下接口与抽象类之间的区别:
1) 接口默认所有的方法为public
和abstract
。我们不能在重写接口方法的时候试图降低方法的访问范围,也不将方法声明为静态方法。只可以是public
和abstract
。
另一方面,抽象类在方法的声明时就显得相对灵活。我们可以定义用protected
去修饰一个抽象方法。此外,我们可以定义静态非抽象方法,以及非抽象的静态方法。
2) 在Java 8以前,接口不能拥有定义完整的方法。接口只提供方法的交互方式,即方法签名。在Java 8中,支持在接口中提供方法的默认实现,需要使用default
关键字。抽象类可以毫无约束地拥有非抽象方法,可以像在普通类中一样使用任意关键字来修饰非抽象方法。
此外,在Java 8中静态方法也可以在接口中实现。
3) 接口需要使用关键字implements
来实现,而抽象类则使用关键字extends
来继承。一个类只能有一个父类,但可以实现多个接口。接口的这个属性经常会被用来在Java中模拟多继承。
四、抽象类和接口的使用
需要记住的是,接口和抽象类的选择通常不是不经过适当的分析而随便选择。二者的使用需要在充分理解我们是手头的问题后作出一个明智的选择。让我们来看一些使用实例:
在抽象类我们可以定义一些行为,所以在应用框架内部抽象类是一个不错的选择。
让我们看看HttpServlet
的例子。如查我们开发一个web应用并使用Servlets技术时,我们必须要继承的主要类型。如我们所知,每个servlet都有一个明确的生命周期环节,如:初始化、服务、销毁。如果在每个servlet中,我们都需要为其初始化和销毁重复编写相同的代码,这是相当痛苦的事。
JDK的设计者们通过提供HttpServlet
抽象类来解决这个问题。这个抽象类提供了servlet初始化和销毁的基本实现。我们只需要根据我们的应用重写特定的方法即可。
让我们再来看看关于接口的使用。接口定义需要提供的方法,实现类需要实现接口中所定义的每一个方法。
当我们只想定义一个实体的特性,并且希望强制所有实现类都具体化这些特性时接口是最好的选择。
关于接口,通常会用Java集合框架中的Map
接口举例。Map
接口只提供一个Map必须要具备的行为准则,如:以键-值对的形式存储数据、可以通过键访问值等。这些行为准则在接口中以抽象方法的形式提供。
Map
的所有实现类,如:HashMap
、HashTable
、TreeMap
或WeakHashMap
,以不同的方式实现了接口中的方法,并体现出了不同的特性。
此外,接口还可以实现职责分离。如:HashMap
实现了3个接口:Map
、Serializable
、Cloneable
。每个接口定义了不同的职责,从而实现类可以选择不同的接口进行实现。