Java抽象类
Java抽象类是无法实例化的类,这意味着我们无法创建抽象类的新实例。抽象类的目的是充当子类的基础。该Java抽象类教程介绍了如何在Java中创建抽象类以及适用于它们的规则。本教程在本文结尾处将更详细地介绍Java抽象类的目的。
声明Java中的抽象类
在Java中,我们可以通过在类声明中添加abstract
关键字来声明类是抽象的。这是一个Java抽象类示例:
public abstract class MyAbstractClass { }
这就是用Java声明抽象类的全部内容。现在我们不能创建MyAbstractClass
的实例。因此,以下Java代码不再有效:
MyAbstractClass myClassInstance = new MyAbstractClass(); //not valid
如果我们尝试在Java编译器上编译以上代码,则会生成错误,表示我们无法实例化MyAbstractClass,因为它是抽象类。
抽象方法
抽象类可以具有抽象方法。我们可以通过在方法声明之前添加abstract
关键字来声明方法抽象。这是一个Java抽象方法示例:
public abstract class MyAbstractClass { public abstract void abstractMethod(); }
抽象方法没有实现。它只是具有方法签名。就像Java接口中的方法一样。
如果类具有抽象方法,则必须将整个类声明为抽象。并非抽象类中的所有方法都必须是抽象方法。抽象类可以混合使用抽象方法和非抽象方法。
抽象类的子类必须实现(覆盖)其抽象超类的所有抽象方法。超类的非抽象方法照原样继承。如果需要,它们也可以被覆盖。
这是抽象类MyAbstractClass的示例子类:
public class MySubClass extends MyAbstractClass { public void abstractMethod() { System.out.println("My method implementation"); } }
注意" MySubClass"如何从其抽象超类" MyAbstractClass"实现抽象方法" abstractMethod()"。
如果子类也是抽象类,则唯一不强制抽象类的子类实现其超类的所有抽象方法的情况。
抽象类的目的
抽象类的目的是充当基类,子类可以扩展这些基类以创建完整的实现。例如,假设某个过程需要3个步骤:
- 行动之前的步骤。
- 那个行动。
- 动作后的步骤。
如果操作前后的步骤始终相同,则可以使用此Java代码在抽象超类中实现三步过程:
public abstract class MyAbstractProcess { public void process() { stepBefore(); action(); stepAfter(); } public void stepBefore() { //implementation directly in abstract superclass } public abstract void action(); // implemented by subclasses public void stepAfter() { //implementation directly in abstract superclass } }
注意action()方法是如何抽象的。 MyAbstractProcess的子类现在可以扩展MyAbstractProcess,并且可以重写action()方法。
调用子类的process()方法时,将执行整个过程,包括抽象超类的stepBefore()和stepAfter()以及子类的action()方法。
当然,MyAbstractProcess
不必是抽象类即可用作基类。 " action()"方法也不必是抽象的。我们本可以使用普通的类。但是,通过使该方法可以实现抽象,从而也可以实现类,我们可以清楚地向此类用户发出信号,即不应按原样使用此类。相反,它应该用作子类的基类,并且抽象方法应在子类中实现。
上面的示例没有为action()方法提供默认实现。在某些情况下,超类可能实际上具有应该重写子类的方法的默认实现。在这种情况下,我们不能使方法抽象。我们仍然可以使超类成为抽象类,即使它不包含任何抽象方法。
这是一个更具体的示例,该示例打开一个URL,对其进行处理,然后关闭与URL的连接。
public abstract class URLProcessorBase { public void process(URL url) throws IOException { URLConnection urlConnection = url.openConnection(); InputStream input = urlConnection.getInputStream(); try{ processURLData(input); } finally { input.close(); } } protected abstract void processURLData(InputStream input) throws IOException; }
注意processURLData()是一个抽象方法,而URLProcessorBase是一个抽象类。 URLProcessorBase的子类必须实现processURLData()方法,因为它是一种抽象方法。
" URLProcessorBase"抽象类的子类可以处理从URL下载的数据,而不必担心打开和关闭与URL的网络连接。这是由" URLProcessorBase"完成的。子类只需要担心处理传递给processURLData()方法的InputStream中的数据。这使实现处理来自URL的数据的类变得更加容易。
这是一个示例子类:
public class URLProcessorImpl extends URLProcessorBase { @Override protected void processURLData(InputStream input) throws IOException { int data = input.read(); while(data != -1){ System.out.println((char) data); data = input.read(); } } }
请注意,子类仅实现了processURLData()方法,仅此而已。其余代码是从" URLProcessorBase"超类继承的。
这是一个如何使用URLProcessorImpl
类的示例:
URLProcessorImpl urlProcessor = new URLProcessorImpl(); urlProcessor.process(new URL("http://Hyman.com"));
调用process()方法,该方法在URLProcessorBase超类中实现。该方法依次调用" URLProcessorImpl"类中的" processURLData()"。
抽象类和模板方法设计模式
我上面用" URLProcessorBase"类向我们展示的示例实际上是Template Method设计模式的示例。模板方法设计模式提供了某些过程的部分实现,当扩展模板方法基类时,这些子类可以完成。