What are some practical examples of abstract classes in java?

29,829

Solution 1

Abstract classes are "half-implementations" of a class. They can be partially implemented with some generic functionality, but leave part of the implementation to the inheriting classes. You could have an abstract class called Animal that has implemented some generic behavior/values such as Age, Name, SetAge(...). You can also have methods that are not implemented (they are abstract), much like an interface.

Interfaces are simply contracts that specify behaviors that should be available for a class. You could have an interface such as IWalker that requires public method Walk(), but no specifics on how it is implemented.

Solution 2

Classes that are entirely abstract (all methods are abstract) are (almost) the same as interfaces (the major difference being they can contain fields and non-public abstract methods, which interfaces cannot). The difference is when you have an abstract class which contains a method which has some common functionality which will be the same for all derived children.

If you want to model a Filesystem, for example, you know that, regardless of the object type, you will have a path for an item. You'd want to have a common implementation for getting that path (no point in writing the same thing over and over again), and leave anything special for the children to implement.

Solution 3

Abstract Classes versus Interfaces

Unlike interfaces, abstract classes can contain fields that are not static and final, and they can contain implemented methods. Such abstract classes are similar to interfaces, except that they provide a partial implementation, leaving it to subclasses to complete the implementation. If an abstract class contains only abstract method declarations, it should be declared as an interface instead.

Multiple interfaces can be implemented by classes anywhere in the class hierarchy, whether or not they are related to one another in any way. Think of Comparable or Cloneable, for example.

By comparison, abstract classes are most commonly subclassed to share pieces of implementation. A single abstract class is subclassed by similar classes that have a lot in common (the implemented parts of the abstract class), but also have some differences (the abstract methods).

An Abstract Class Example

In an object-oriented drawing application, you can draw circles, rectangles, lines, Bezier curves, and many other graphic objects. These objects all have certain states (for example: position, orientation, line color, fill color) and behaviors (for example: moveTo, rotate, resize, draw) in common. Some of these states and behaviors are the same for all graphic objects—for example: position, fill color, and moveTo. Others require different implementations—for example, resize or draw. All GraphicObjects must know how to draw or resize themselves; they just differ in how they do it. This is a perfect situation for an abstract superclass. You can take advantage of the similarities and declare all the graphic objects to inherit from the same abstract parent object—for example, GraphicObject, as shown in the following figure.

Classes Rectangle, Line, Bezier, and Circle inherit from GraphicObject

Classes Rectangle, Line, Bezier, and Circle inherit from GraphicObject

[...]

Source: The Java™ Tutorials

Solution 4

Surprisingly, many examples/explanations given here do not provide good arguments for using an abstract class. Merely putting common fields/methods in a superclass does not require it to be abstract. Also (start rant), shame on supposedly knowledgeable engineers still coming up with Animal / Vehicle / Figure hierarchies to 'explain' object oriented concepts. These types of examples are very misleading because they point you in the wrong direction; you generally should NOT favour straight subclassing because it creates a very tight coupling between the classes. Rather use collaboration (rant ends).

So what do I think is a good use case for an abstract class? One of my favorite examples is an application of the 'template method' GoF pattern. Here you want to specify the generic flow of an algorithm once, but allow multiple implementations of the individual steps. Here an example I just put together of a VirusScanEngine containing the main virus scanning algorithm (find the next virus, either delete or report it, continue until scan is complete), and a LinearVirusScanner which implements the required algorithm steps (findVirus, deleteVirus and reportVirus). My apologies to all developers really working on virus scanning software for this horrendous simplification.

import java.util.Arrays;

public abstract class VirusScanEngine {

    public static void main(String[] args) {

        byte[] memory = new byte[] { 'a', 'b', 'c', 'M', 'e', 'l', 'i', 's', 's',
                'a' , 'd', 'e', 'f', 'g'};
        System.out.println("Before: " + Arrays.toString(memory));
        new LinearVirusScanner().scan(memory, Action.DELETE);
        System.out.println("After: " + Arrays.toString(memory));
    }

    public enum Action {
        DELETE, REPORT
    };

    public boolean scan(byte[] memory, Action action) {

        boolean virusFound = false;
        int index = 0;
        while (index < memory.length) {

            int size = findVirus(memory, index);
            if (size > 0) {
                switch (action) {

                case DELETE:
                    deleteVirus(memory, index, size);
                    break;
                case REPORT:
                    reportVirus(memory, index, size);
                    break;
                }
                index += size;
            }
            index++;
        }
        return virusFound;
    }

    abstract int findVirus(byte[] memory, int startIndex);

    abstract void reportVirus(byte[] memory, int startIndex, int size);

    abstract void deleteVirus(byte[] memory, int startIndex, int size);
}

and

public class LinearVirusScanner extends VirusScanEngine {

    private static final byte[][] virusSignatures = new byte[][] {
            new byte[] { 'I', 'L', 'O', 'V', 'E', 'Y', 'O', 'U' },
            new byte[] { 'M', 'e', 'l', 'i', 's', 's', 'a' } };

    @Override
    int findVirus(byte[] memory, int startIndex) {

        int size = 0;
        signatures: for (int v = 0; v < virusSignatures.length; v++) {

            scan: {
                for (int t = 0; t < virusSignatures[v].length; t++) {

                    if (memory[startIndex + t] != virusSignatures[v][t]) {
                        break scan;
                    }
                }
                // virus found
                size = virusSignatures[v].length;
                break signatures;
            }
        }
        return size;
    }

    @Override
    void deleteVirus(byte[] memory, int startIndex, int size) {

        for (int n = startIndex; n < startIndex + size - 1; n++) {
            memory[n] = 0;
        }
    }

    @Override
    void reportVirus(byte[] memory, int startIndex, int size) {

        System.out.println("Virus found at position " + startIndex
                + " with length " + size);
    }
}

Solution 5

As KLE correctly explained, the main difference between interface and abstract class is that an abstract class may contain fields and method bodies, while an interface may only contain method signatures (and constants, i.e. public static final fields).

Another important distinction is that a class can implement multiple interfaces, but it can only (directly) inherit from one class (abstract or not). So for things which people will probably use in addition to other functionality, an interface makes more sense than an abstract class. See e.g. the interfaces Comparable in the JDK.

As an example:

In the system we develop, we have a class for starting a data import. We have many different kinds of data imports, but most have some things in common: They read data from a file, they write it to the database, they produce an import protocol etc.

So we have an abstract class "Import", which contains implemented methods for things like writing protocol entries, finding all files to import, deleting processed import files etc. The specifics will be different for each import, so there are abstract methods that serve as extension hooks, e.g. getFilenamePattern() which is used by the reading method to find the files that can be imported. getFilenamePattern is implemented in the concrete subclass, depending on what kinds of files need to be imported.

That way, the shared import functionality is in one place, while the specifics for one kind of import are separate.

Share:
29,829
gregory boero.teyssier
Author by

gregory boero.teyssier

https://ali.actor

Updated on July 09, 2022

Comments

  • gregory boero.teyssier
    gregory boero.teyssier almost 2 years

    When and why should abstract classes be used? I would like to see some practical examples of their uses. Also, what is the difference between abstract classes and interfaces?