当前位置 博文首页 > 程序员石磊:java面对对象入门(8)-接口vs抽象类区别
完整文档版教程请移步语雀
用最简单的话来说,一个抽象类就是使用keyword声明为abstract的abstract
。它可能包含也可能不包含任何抽象方法。JVM将抽象类标识为不完整类,该类尚未定义其完整行为。声明一个类abstract
仅强制执行一件事:您不能创建此类的实例,仅此而已。
那么,为什么还要费心创建一个根本无法实例化的类呢?答案在于解决某些关键设计问题的方法。我们将在本文后面介绍这一部分。
abstract class TestAbstractClass
{
public abstract void abstractMethod();
public void normalMethod()
{
//method body
}
}
在这里,我们TestAbstractClass
有两种方法,一种是抽象方法,第二种是普通方法。抽象方法。在类中使用抽象方法将迫使您将类声明为抽象本身。
一个抽象方法,是未取代实施的方法。抽象方法给类增加了不完整性,因此编译器希望将整个类声明为抽象。
在应用程序中使用抽象类的唯一方法是扩展此类。如果不abstract
再次声明其子类,则可以实例化。子类继承了超类的行为,并且超类可以保留对子类的引用的功能在很多方面增加了抽象类的重要性。
接口是大多数Java API的另一个基本构建块。您将其命名为collection,I / O或SWT,您可以在任何地方看到它们的运行情况。
接口定义合同,实现类需要遵守这些合同。
这些合同本质上是未实现的方法。Java已经有一个未实现方法的关键字,即_abstract_。Java规定任何类都可以实现任何接口,因此在接口中声明的所有方法仅需是公共的。
public interface TestInterface
{
void implementMe();
}
对于上述接口,任何实现类都需要重写implementMe()
方法。
当实现一个接口并且不重写该方法即声明实现类本身时,只有一种情况abstract
。
抽象类
public abstract class TestMain implements TestInterface
{
//No need to override implement Me
}
否则,您必须implementMe()
在您的类中实现该方法,而没有任何其他例外。
非抽象类
public class TestMain implements TestInterface
{
@Override
public void implementMe() {
// TODO Auto-generated method stub
}
}
让我们记下抽象类和接口之间的差异以便快速查看:
extends
,而为了实现接口关键字是implements
。一个类只能扩展一个类,但可以实现任何数量的接口。在Java中,此属性通常称为多重继承的模拟。abstract
,不能实例化;Java抽象类也无法实例化,但是如果存在main()则可以调用它。接下来,如果我们既有抽象方法又有主类,可能会有一个问题,我们可以尝试从中调用抽象方法main()
。但是这种尝试将失败,因为main()
方法始终是静态的,而抽象方法永远不会是静态的,因此您永远无法访问静态方法内部的任何非静态方法。
始终记住,在接口或抽象类之间进行选择既不是/也不是方案,在这种情况下,选择未经适当分析的任何人都会产生相同的结果。了解当前问题后,必须非常明智地做出选择。让我们尝试在这里添加一些智慧。
抽象类使您可以定义一些行为。它使它们成为应用程序框架内的优秀候选人。
让我们以HttpServlet为例。如果要使用Servlets技术开发Web应用程序,则必须继承该类。众所周知,每个servlet都有明确的生命周期阶段,即初始化,服务和破坏。如果我们创建了每个servlet,我们必须一次又一次地编写关于初始化和销毁的同一段代码。当然,这将是一个很大的痛苦。
JDK设计人员通过制作HttpServlet
抽象类来解决此问题。它具有为初始化Servlet和销毁Servlet而编写的所有基本代码。您只需要重写某些方法即可在其中编写与应用程序处理相关的代码。有道理吧!
可以使用界面添加上述功能吗?不,即使可以,对于大多数无辜的程序员来说,设计也将是一个地狱。
现在,让我们看一下接口的用法。接口仅提供合同,实现类的责任是实现提供给它的每个合同。
如果只想定义class的特征,并且要强制所有实现实体实现这些特征,那么接口是最合适的。
我想以Map
集合框架中的接口为例。它仅提供规则,以及map在实践中应如何表现。例如,它应存储键值对,应使用键等访问该值。这些规则在接口中采用抽象方法的形式。
所有实现类(例如HashMap,HashTable,TreeMap或WeakHashMap)均以不同方式实现所有方法,因此与其他方法相比具有不同的功能。
同样,接口可用于定义职责分离。例如,HashMap
实现3个接口:Map
,Serializable和Cloneable。每个接口定义了各自的职责,因此实现类选择要实现的对象,因此将提供有限的功能。
使用Java 8,您现在可以在接口中定义方法。这些称为默认方法。默认方法使您可以向库的接口添加新功能,并确保与为这些接口的较早版本编写的代码二进制兼容。
顾名思义,Java 8中的默认方法就是默认的。如果不重写它们,则它们是调用方类将调用的方法。
默认方法
public interface Moveable {
default void move(){
System.out.println("I am moving");
}
}
在上面的示例中,Moveable
接口定义了一种方法,move()
并且还提供了默认实现。如果有任何类实现此接口,则无需实现它自己的move()
方法版本。它可以直接调用instance.move()
。
public class Animal implements Moveable{
public static void main(String[] args){
Animal tiger = new Animal();
tiger.move(); //I am moving
}
}
并且,如果类愿意定制行为,那么它可以提供自己的定制实现并重写该方法。现在将调用它自己的自定义方法。
public class Animal implements Moveable{
public void move(){
System.out.println("I am running");
}
public static void main(String[] args){
Animal tiger = new Animal();
tiger.move(); //I am running
}
如果您看到了,我们现在也可以提供带有接口的部分实现,就像抽象类一样。因此,从本质上说,接口与抽象类之间的界限变得非常狭窄。它们现在提供几乎相同的功能。
现在,只有一个很大的不同,即您不能扩展多个类,而可以实现多个接口。除了这种差异之外,您还可以通过接口实现任何可能的功能,这些接口可以使抽象类成为可能,反之亦然。
希望您在Java中找到有关接口和抽象类的足够信息。
学习愉快!
更多精彩请关注公众号【lovepythoncn】