In Chapter 6, we have looked at the keyword final
, let us now look at another keyword in Java called abstract
. The keyword abstract
in a sense is opposite of final
. It is a modifier only for methods and classes. The modifiers abstract
and final
cannot be used together. A method or a class cannot be declared to be both abstract
and final
. A final
method prevents overriding, whereas an abstract
method promotes overriding. A final
class prevents inheritance, whereas an abstract
class promotes inheritance.
What is the meaning of declaring a method as abstract
. When we declare a method as abstract
, then we do not provide an implementation of the method, and the method would be required to be overridden in a non-abstract sub-class. A non-abstract class cannot have any abstract methods, whether inherited or declared.
An abstract class is a class that is like all normal classes, but has two differences. One, an application cannot create an instance of this class. Only instances of its non-abstract sub-classes can be created. Two, an abstract class can have abstract methods, which are not allowed in a non-abstract class.
Let us try to understand the use of abstract methods. Methods are like the operators of a data type. Now, if we look at the specification for the C language, we find that it says that the arithmetic operators are defined for all the numeric types. There is no type called numeric type, which is being used directly, but byte, short, int, long, float, double and char are the numeric types. These are the sub-types of the numeric type. Here numeric type is an abstract type, which has the operators like addition, subtraction, multiplication and division. The specification for the numeric type does not specify how these operations are to be performed, it is simply a specification that such operators need to be supported by any sub-type (kind) of numeric type. There will be different ways of doing addition, subtraction, multiplication and division for different kinds of numeric types. The addition for integral types differs from the way addition is done for the floating point types. Similarly, an abstract class is an abstract data type (like the numeric type above), which can have abstract methods (like addition, subtraction, etc. above), these abstract methods are simply declaration, and does not have any implementation.
Let us take another example of an abstract type. Let us say we have a class called Vehicle
, then an instance of Vehicle
is never created. The instances created are of some sub-class of Vehicle
. Every Vehicle
can have a method called start
(), run
(), brake
(), etc. But how to start a vehicle cannot be specified in the Vehicle
class itself. There is no implementation of these methods in the Vehicle
class. It has just a declaration about the return type and the kind of parameters required for the method. Each sub-class will have its own different implementation of the start, run and brake methods. So, these methods would be specified as abstract
in the Vehicle
class, indicating that all non-abstract sub-classes of vehicles must have these methods implemented.
There are two cases in Java where a method is simply declared and implementation is not written. One is when the method is declared as abstract
, and the other is when the method is declared as native. The native methods are methods whose implementation is not written in Java, but is written in some native language, mostly C or C++
.
1 abstract class Vehicle { // an abstract class may have abstract methods. 2 abstract void start(); // abstract methods do not have an implementation. 3 abstract void run(); 4 abstract void brake(); 5 … 6 }
In the class hierarchy given in Figure 7.1, we have Vehicle
as a super-class, and since this class has abstract methods, this class would have to be declared as abstract
. It has a sub-class called Car
. The class Car
may not declare any new abstract methods and may implement some of the abstract methods from the super-class, but if it has still some inherited abstract methods (abstract method not overridden), then the class Car
would also have to be declared as abstract
. Now let us say that we have the sub-class MarutiCar
, which is a sub-class of Car
, and it may not have any abstract methods declared, and it overrides all the abstract methods from the super-class to be non-abstract. So, the class MarutiCar
, does not have any abstract methods of any form, but we may still decide to declare it abstract
, since we would not like anyone to directly create instances of this class. Instances of MarutiCar
are not created; what are created are instances of various models like the Maruti800
, which is a type of MarutiCar
. Perhaps, Maruti800
, which is a basic model simply inherits all the functionality from the super-class and may not even add or override methods from the super-class, and the overriding or adding of new methods may be done in other sub-classes like MarutiZen
, etc. Here we do not create instances of MarutiCar
, but we do create instances of Maruti800
, MarutiZen
and other types of MarutiCar
; so it is necessary that the classes Maruti800
, MarutiZen
and other types of MarutiCar
do not have any abstract methods. Therefore, the following conditions can be summarized for declaring a class as abstract
:
Figure 7.1 Sub-classes of Vehicle
class
abstract
if we have declared some abstract methods in a class. A non-abstract class cannot have any abstract
methods.abstract
even if there are no abstract methods declared in the class, but it has some abstract methods that have not been overridden to be non-abstract.abstract
even if the class has no abstract
methods declared, and there are no abstract
methods that have been inherited. This may be done to prevent creating instances of the class and it enforces the creation of sub-classes.Even though we do not create instances of an abstract
class, still, an abstract
class can always have a constructor. The constructors of an abstract
class will be used from the constructor of its sub-classes.
A common question at this stage is what is the use of an abstract
method and why declare a method when we are not writing an implementation of the method? Let us look at an example where an abstract
method is useful. Let us say we have an abstract
class Vehicle
as given below:
1 abstract class Vehicle { 2 abstract double getLoad(); // a method return the load of a vehicle 3 abstract void start(); 4 abstract void run(); 5 abstract void brake(); 6 }
and we also have a class called Bridge
as given below:
1 class Bridge { 2 double maxLoad; 3 Bridge(double maxLoad) { 4 this.maxLoad = maxLoad; 5 } 6 boolean canCross(Vehicle v) { 7 return v.getLoad() < maxLoad; 8 } 9 }
In the above example, whenever we create a Bridge
instance, we would have to specify the maxLoad
that can go over the Bridge
. Now, whenever a Vehicle
approaches the Bridge
, it may first check whether the Vehicle
is allowed to go over the Bridge
by checking with the canCross
() method of the Bridge
class. The canCross
() method uses the getLoad
() method from the Vehicle
. If we did not have the abstract
method getLoad
() in the Vehicle
then the canCross
() method would have to be overloaded for each non-abstract sub-class of the Vehicle
class where the getLoad
() method would be defined. Here, it is sufficient to know that any Vehicle
instance would always have a method getLoad
(), since an instance can only be created from a non-abstract class, so it would also imply that an implementation of the getLoad
() method would always be available for any instance of a non-abstract sub-class of Vehicle
.
EXERCISE 7.1 Declare the Account
class of Exercise 6.1 to be abstract
. Also recompile the TestAccount
class to test that the instances of Account
are not created directly, i.e. new Account(…)
, should give a compilation error.
The updated Account
class is now given in Listing 7.1.
Listing 7.1. Account
class as abstract class
1 2 abstract class Account { 3 4 int accountNumber; 5 String name; 6 double balance; 7 8 Account(int acno, String n, double openBal) { 9 this.accountNumber = acno; 10 this.name = n; 11 this.balance = openBal; 12 } 13 14 int getAccountNumber() { 15 return this.accountNumber; 16 } 17 18 String getName() { 19 return this.name; 20 } 21 22 double getBalance() { 23 return this.balance; 24 } 25 26 void deposit(double amt) { 27 this.balance += amt; 28 } 29 30 boolean withdraw(double amt) { 31 if (this.balance < amt) { 32 return false; 33 } 34 this.balance -= amt; 35 return true; 36 } 37 38 void display() { 39 System.out.println("Account:"+this.accountNumber+","+this. name+","+this.balance); 40 } 41 42 static int lastAccountNumber = 1000; 43 44 Account(String n, double openBal) { 45 this(++lastAccountNumber, n, openBal); 46 } 47 }
In Java, we do not have multiple inheritance of classes. A class cannot have more than one direct super-class. When we define the class, we can specify only one class name in the extends
clause of the class definition.
Now looking at the initial class inheritance given for the Vehicle
class, we also identify another sub-class of Vehicle
class called Aeroplane
. Now this class is not only a Vehicle
, but it is also a FlyingObject
. There are many other things that are flying objects.
So here, we have Aeroplane
, which has two direct super-types. One, Vehicle
and another, FlyingObject
. What is a FlyingObject
? FlyingObject
is anything that can fly. It is identified by the functionality which it must support. There are many things which can be FlyingObject
, but, each type of FlyingObject
will have its own implementation of the fly
() method, so, the fly
() method in the FlyingObject
will be abstract
. We cannot implement the fly
() method for the FlyingObject
, also, we cannot have any instance variables in the FlyingObject
; different types of FlyingObject
will use different things for flying. Some may use wings, and yet some may not be using wings. There is no structure available for FlyingObject
. FlyingObject
will be a type, which has no instance variables and has only abstract
method (here it has the fly
() method as an abstract method). When we have such data types that have no instance variables and only abstract
methods (no, non-abstract methods), then these types are defined as interfaces (Figure 7.2).
Figure 7.2 Sub-classes of Vehicle
class
What is the difference between an abstract
class and an interface? An interface is a special case of an abstract
class, which can only have abstract
methods and static constants and can be used in multiple inheritance of types. Out of the various members for a class which we know about, only abstract
methods and static constants are allowed in an interface. There are a few other members which can also go in an interface, which we will talk about when we look at the nested types in Chapter 12. An interface cannot contain any kind of method implementations (non-abstract methods). All the members in an interface are always public
. We will be looking at the meaning of various access specifiers in Chapter 9. An interface for the FlyingObject
may be defined as follows:
1 interface FlyingObject { 2 void fly(); 3 }
All interfaces are implicitly abstract
and we need not explicitly declare an interface to be abstract
. Also any method declaration in an interface is always public
and abstract
, we need not explicitly declare them as abstract
. When we declare a variable in an interface then it is implicitly public static
and final
, it may not be explicitly declared so. Therefore, the above definition of FlyingObject
may also have been declared as given below:
1 abstract interface FlyingObject { 2 public abstract void fly(); 3 }
The inheritance rules for classes and interfaces are as follows:
implements
clause.extends
keyword, then the Object
class (which we will look at, in Chapter 8) is considered as the super-class.Figure 7.3 Interface FlyingObject
implemented by unrelated classes
Thus, the inheritance relation between classes forms a tree structure, with Object
class as the root, and the interfaces are some kind of specification, which can be put anywhere in the hierarchy of the classes. Therefore, for example we have FlyingObject
interface being implemented, in totally unrelated classes.
Here, the FlyingObject
is implemented by different types of classes, which are kind of Mammals
, Toys
or Vehicle
, etc. Interface is like a pure abstract class, which can never have any kind of implementation (non-abstract methods) (Figure 7.3). Note that static methods cannot be declared to be abstract
. In Java we do not have multiple inheritance of classes, but we have multiple inheritance of data types using interfaces. Some languages allow multiple inheritance of classes but then they also have cases, which can lead to ambiguity in case of inheritance. There is also a very famous diamond problem, related to multiple inheritance of classes. In case of Java, since the interfaces do not have implementation, and a class can have only one direct super-class, it would not be possible to inherit more than one kind of implementation of any method from the super-class. Abstract methods may be inherited from multiple interfaces that the class implements. Only abstract classes can inherit abstract methods from an interface, a non-abstract class needs to override all the abstract methods declared in the interface that it implements, such an overriding is allowed to be inherited from the super-class.
Interfaces are also used to check if a certain operation can be performed on an instance or not; example, Cloneable
interface, which is discussed in Chapter 8.
Another very good use of interface is the Comparable
interface, which is discussed in Chapter 10.
Misconception Abstract class must have at least one abstract method.
Fact Any class may be declared to be abstract to prevent instantiation of the class without sub-classing.
Misconception Abstract class cannot have a constructor.
Fact Every class has at least one constructor. The constructor in an abstract class will be used from the constructors of its sub-class.
extends
is used to inherit from one super-class, whereas the keyword implements
is to indicate the super-interfaces for a class.extends
is used by an interface to inherit from other interfaces.static
constant(final
) variables. All members in an interface are always public
.abstract
class must have at least one abstract
method.abstract
class.abstract
methods may not be declared in a non-abstract class, but may be inherited from an abstract super-class.abstract
and final
.interface
, super-class and sub-class.18.218.151.44