Java抽象类

时间:2020-01-09 10:35:40  来源:igfitidea点击:

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设计模式的示例。模板方法设计模式提供了某些过程的部分实现,当扩展模板方法基类时,这些子类可以完成。