简体   繁体   中英

What are some practical examples of abstract classes in java?

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?

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.

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.

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.

类Rectangle,Line,Bezier和Circle继承自GraphicObject

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

[...]

Source: The Java™ Tutorials

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);
    }
}

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, ie 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 eg 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, eg 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.

http://java.sun.com/docs/books/tutorial/java/IandI/abstract.html

http://java.sun.com/docs/books/tutorial/java/concepts/interface.html

In short, an abstract class can be partially implemented, an interface cannot. More details in the links above.

An interface contains no implementation at all.

An abstract class may contain some implementation, that is useful to all subclasses, but not be complete : it needs to be completed in some way in the subclasses.
Where the interface lets you use polymorphism on several classes, abstract class also lets them reuse code .

     public abstract class Figure {
        protected Point position;

        public abstract void draw();
     }

     public class Square extends Figure {
       // position is usable

       public void draw() {
         // this method must be implemented, for Square not to be abstract
       }

       // here is other code
     }

Another difference is that a class can only have one superclass , but implements many interfaces. This can be a limiting factor.

If you need to wrap your head around the concept of abstract classes, take a look at the Swing UI toolkit (or at AWT) in the standard library.

Because you can imagine what can be visualized (eg, a button, a label), it's easy to contrast it with the things that can't be instantiated (eg, a JComponent).

You can restrict the order of execution of an instruction with specific steps, but allow delegation for the behavior of each step:

public abstract class Instruction {

    void perform() {
        firstStep();
        secondStep();
        thirdStep();
    }

    abstract void firstStep();

    abstract void secondStep();

    abstract void thirdStep();

}

When and why should abstract classes be used?

Below post answers your query:

Interface vs Abstract Class (general OO)

I would like to see some practical examples of their uses.

When You want to share code among several closely related classes

One practical example : Template method implementation in JDK Reader.java class

Have a look at below post:

Template design pattern in JDK, could not find a method defining set of methods to be executed in order

what is the difference between abstract classes and interfaces?

Refer to this post:

How should I have explained the difference between an Interface and an Abstract class?

In my own thinking, the correct way is to approach this question is to determine the context you are dealing with regarding the domain or entity objects first, namely what is your use case?

In my personal experience, I do this using a top down and then bottom up approach. I start looking for inheritance by looking at the use case and seeing what classes I will need. Then I look to see if there is a superClassOrInterfaceType (since both classes and interfaces define types, I'm combining them into a one word for simplicity. Hopefully it doesn't make it more confusing) domain object that would encompass all the objects, as in a superClassOrInterfaceType of vehicle if I'm working on a use case dealing with subtypeClassOrInterfaceTypes like: cars, trucks, jeeps, and motorcycles for example. If there is a hierarchy relationship, then I define the superClassOrInterfaceType and subtypeClassOrInterfaceTypes.

As I said, what I generally do first is to look for a common domain superClassOrInterfaceType for the objects I'm dealing with. If so, I look for common method operations between the subtypeClassOrInterfaceTypes. If not, I look to see if there are common method implementations, because even though you may have a superClassOrInterfaceType and may have common methods, the implementations may not favor code reuse. At this point, if I have common methods, but no common implementations, I lean towards an interface. However, with this simplistic example, I should have some common methods with some common implementations between the vehicle subtypeClassOrInterfaceTypes that I can reuse code with.

On the other hand, if there is no inheritance structure, then I start from the bottom up to see if there are common methods. If there are no common methods and no common implementations, then I opt for a concrete class.

Generally, if there is inheritance with common methods and common implementations and a need for multiple subtype implementation methods in the same subtype, then I go with an abstract class, which is rare, but I do use it. If you just go with Abstract classes just because there is inheritance, you can run into problems if the code changes a lot. This is detailed very well in the example here: Interfaces vs Abstract Classes in Java , for the different types of domain objects of motors. One of them required a dual powered motor, that required multiple subtype implementation methods to be used in a single subtype class. In other words, a single class needed implementation methods from both solar powered and battery powered motors, which is modeling behaviors and not something you want to do with Abstract classes.

To sum it all up, as a rule you want to define behaviors (what the objects will do) with interfaces and not in Abstract classes. Abstract classes focus on an implementation hierarchy and code reuse.

Here are some links that go into greater details on this.

Thanks Type & Gentle Class

The Magic behind Subtype Polymorphism

Maximize Flexibility with Interfaces & Abstract Classes

Interfaces vs Abstract Classes in Java

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM