What
is an Abstract Class and when should I use it?
|
Abstract classes are useful when you
want to encapsulate a set of common features in one superclass, and you want some concrete
methods in the superclass itself.
If your abstract class needs no concrete methods, or you
want a subclass to implement multiple superclasses, then an interface may
be more appropriate. |
Recommended
Embedded uses
|
You might have an abstract Motor
class, with subclasses SteeringMotor, DriveMotor, etc. This would be a good way
to encapsulate Motor functionality.
Device or I/O drivers commonly use abstract classes and/or interfaces. |
Tips
for embedded use
|
- Consider the hardware (if any) which relates to your classes and pattern your objects
after it. For example, if there is only one possible instance of the hardware (a
keyboard for example), then make it a static class and don't confuse users by allowing
nonsensical multiple instances.
- Will your API evolve over time? An interface may be the wrong choice, since every
time you add new methods, you break all existing uses. Consider an abstract class
or a combination of the two.
- Does your superclass naturally want to contain common generic methods and fields
which will be useful to all users? If so, don't duplicate such code by forcing
an interface on this situation - use an abstract class and create one place to
maintain such shared code.
|
Abstract Classes vs Interfaces |
|
Abstract Class |
Interface |
|
Abstract classes |
Interfaces are just a specification or template, with no implementation. |
Subclass can extend or implement multiple superclasses? |
No, a Java class can extend only one superclass. |
Yes, a Java class can implement any number of interfaces |
What a subclass does |
subclasses extend the superclass |
subclasses implement the superclass |
Common examples |
javax.comm.CommPort |
javax.comm.SerialPortEventListener, java.io.DataInput,
java.io.DataOutput, java.lang.Runnable, java.util.Enumeration, javax.microedition.io
such as Connection,
Datagram, InputConnection, StreamConnection. |
Constructor? |
Yes, but be careful if you make an abstract class's constructor
private, since private methods of an abstract class are not abstract. |
No, since an interface cannot be instantiated. |
Can contain concrete methods? |
Yes |
No, all methods of an interface are
abstract, though they need not use the 'abstract' keyword. |
Subclass must implement all (abstract) methods in superclass? |
Yes, so you know that
any subclass has implementations of all the abstract methods in a superclass.
You'd hope that you could then count on these mehtods all working as expected in
every
subclass. Sadly, this is often not the case -- for example, javax.comm.SerialPort
classes are often "implemented" to satisfy the superclass when in fact the implementation
has no function
- for example, setting options such as
number of stop bits, parity, etc, which are not supported by the underlying hardware. |
No, so you have no idea if a subclass
implements any particular interface methods. But if a class does not implement all
interface methods then it inherits any such abstract methods and the class must
be declared abstract. |
Can have private or protected methods? |
Yes, but these must be
concrete methods |
No, all interface methods are implicitly
public. |
Subclasses can contain methods not in the superclass? |
Yes, but access can be
a bit tricky. I'm still looking into this. |
Yes, no restrictions. |
Can include fields? |
Yes |
Yes, but only if static and final. |
Maintainability concerns |
- If you add abstract methods to an existing abstract class,
you will break any existing subclasses.
- Adding concrete methods does not affect existing
subclasses.
|
If you add abstract methods to an existing interface, you will break
any existing uses of that interface. Consider this drawback if you expect your API
to evolve over time. |
Abstract Classes - key points |
- Any class with an abstract method is an abstract
class.
- You can't instantiate an abstract class, only its subclass(es).
- A subclass of
an abstract class can only be instantiated if it overrides each of
the abstract methods of the superclass and provides an implementation for each
of them. This guarantees that any subclass will have (hopefully valid
and useful) implementations of each abstract method.
- If an abstract class doesn't
implement all of the superclass methods, then it is also abstract (and therefore
can't be instantiated).
- Static,
private, and final methods cannot be abstract, since these kinds
of methods can't be overridden by a subclass. But such methods can be class methods
(concrete methods) of an abstract class.
- An abstract class can have concrete
methods.
- It doesn't make sense for an abstract class to be static, since a static class
can't be instantiated. If you only need one instance (the static class itself)
then why make it abstract? But it could make a lot of sense for a subclass to be
static. An example would be a static SteeringMotor class which extends the abstract
Motor class.
|
Examples |
Abstract Class |
Interface |
Here is an abstract class which defines a generic eeprom memory which is used in JCX tagging.
This portion has one concrete method (the constructor) and two abstract methods.
abstract class Eeprom {
/**integer represents the end of the systronix sacred area*/ private int endIndexSacred=-1;
/** * takes in a JCX address, note that any subclass MUST call super(int JCXaddress, SpiSlaveSelect JCXchip_select) * and it must create a SpiSlaveDevice to attach to port */ public Eeprom(int JCXaddress, SpiSlaveSelect JCXchip_select) { baseAddr=JCXaddress; cs=JCXchip_select; endIndexSacred=-1; }
/** * @return int the size of the eeprom in bytes */ abstract public int getEepromLength();
public abstract boolean blankCheck();
}
|
|
Here is a portion of one subclass which implements a driver for a specific
eeprom (25LC160) used on JCX boards. This particular subclass is non-static, since each
JCX I/O board contains tagging memory, so there is typically one instance of this eeprom
per I/O board, with up to five I/O boards per JCX system.
class Jcx25LC160 extends Eeprom {
/** * number of bytes in EEPROM, 0 inclusive so 2047 means 2048 bytes */ public final int EEPROM_LENGTH = 2048;
/** * returns the size of the eeprom in bytes * @return int */ public int getEepromLength() { return EEPROM_LENGTH; }
/** * Determine if an eeprom is blank (contains all 0xFF) * @return true if blank, false if not */ public boolean blankCheck() { int nonblank = 0; int data; for (int adr = 0; adr < EEPROM_LENGTH; adr ++) { try { data = read (adr); if (0xff != data) { nonblank++; System.out.println ("Nonblank @" + adr + ": 0x" + Integer.toHexString(data)); } } catch (IOException ioe) { ioe.printStackTrace(); } } if (nonblank > 0) { // for debug only System.out.println (nonblank + " nonblank locations found; blank check fails!"); return false; } return true; }
} |
|
Combining Interfaces and Abstract Classes |
It's
common and acceptable to mix these two, typically by creating an abstract class which
implements an interface. |
|
|
|