You are on page 1of 10

INHERITANCE

Recapitulation:
Inheritance is a reusability mechanism in object-oriented programming in which the common
properties of various objects are exploited to form relationships with each other. The abstract and
common properties are provided in the superclass, which is available to the more specialized
subclasses. For example, a color printer and a black-and-white printer are kinds of a printer (single
inheritance); an all-in-one printer is a printer, scanner, and photocopier (multiple inheritance). It
should be noted that Java does not support multiple inheritance but does support multiple-interface
inheritance

When we say that a class B is inherited from another class A, then class B is referred to as a
derived class (or subclass) and class A is called as a base class (or superclass). By inheritance,
the derived class receives the behaviour of the base class, such that all the visible member
methods and variables of the base class are available in the derived class. Apart from the inherited
behavior, the derived class specializes its behavior by adding to or overriding base class behavior.

Inheritance is a powerful feature that allows new classes to be derived from existing ones.
The derived class inherits the interface of the base class and can add new methods or
change existing ones to suit its purpose. Any number of classes can be added to an
inheritance scheme to produce a hierarchy (the collection of all classes extending from a
common super class) of related types. The Java implementation of inheritance supports
polymorphism, which allows objects of different types to be treated as if they were of the
same type.

Inheritance provides a mechanism for new classes to use the data and methods of the
existing classes. For example if a manager is an object with a name, a salary, a hire date
and a secretary name, then class Manager can inherit the name, hire date and salary
structure from the Employee class and just add a new private field for the secretaryName
data. Inheritance is effected using the keyword, “extends” for example:

public class Manager extends Employee


{
// methods
private String secretaryName;

}
Class Manager inherits all the data and methods of class Employee. The existing class is
termed the superclass, base class, or parent class and the new class is called the subclass,
derived class or child class. So Employee contains the set of all Managers or Employee is
a superset of the set of Managers.

We need constructor methods for our new class Manager. We might propose the
following constructor:

Prepared by Prophet Zanamwe N @2014


public Manager(String aName, double aSalary, int year, int month, int day, String
aSecretaryName)
{

name = aName; // Error


salary = aSalary; // Error
hireDate = new Day(year, month, day); // error
secretaryName = aSecretaryName;

But this does not compile because name and salary are private data of class Employee. A
subclass has no rights of access to the private data of a super class. Like any other class
the subclass can only access private data through the interface provided in this case we
need to use the constructor methods of class Employee. A subclass refers to the super
class using the keyword “super”. Accordingly, we can write the constructor as follows:

public Manager(String aName, double aSalary, String aSecretaryName, int year, int
month, int day)
{ super(aName, aSalary, year, month, day);
secretaryName = aSecretaryName;

When used to reference a superclass constructor the keyword super must be the first
statement in the method.

The order and types of actual parameters MUST correspond to the order and types of
formal parameters for the super class constructor.

We could write the default constructor for the Manager class similarly:
public Manager()
{
super();
secretaryName = “”;
}
In fact we do not need to include the reference to the super class’s default constructor as
the compiler will automatically include this for us.

Subclasses inherit all the data and methods of their super classes. For example, a
Manager object inherits the print() method of the Employee class:

Manager m = new Manager()


m.print();

Prepared by Prophet Zanamwe N @2014


The print method of the class Employee prints the name, hire date and salary data of the
Employee class. But when we print a Manager object we want to print the data fields of
the Manager object as well as the inherited data fields. We can declare a print() method in
the Manager class with the same signature (name and parameter list) as the super class
method. In this method we will first call the super class print() method to print the super
class data fields:

public void print()


{
super.print();
System.out.println(secretaryName);
}

Methods with the same signature may exist at all levels of the inheritance hierarchy (but
not in the same file); methods in the subclass simply hide or shadow or override those in
the super classes. But subclass and super class cannot have methods with the same
signature but different return types.

Polymorphism
Recapitulation:
The Greek roots of the term polymorphism refer to the “several forms” of an
entity. In the real world, every message you communicate has a context.
Depending on the context, the meaning of the message may change and so may
the response to the message. Similarly in OOP, a message can be interpreted in
multiple ways (polymorphism), depending on the object.

For example, in function overloading (one of the polymorphic constructs in Java),


you can provide methods with the same name but with different numbers of
arguments or types of arguments. The concept is simple, yet it provides a lot of
power and flexibility to the programmer. The call for the same method, behaves
differently based on the provided arguments; this is an example of compile-time
polymorphism.

Let’s assume that you have a method named show() in a base class. The show()
method returns the details of an object. Hence, show() is implemented
(overridden) in all the derived classes of base class. A base class reference can
point to any derived class object. When you call the show() method from the
base class reference, it results in calling the show() method of the actual object
type (i.e. the dynamic type of the object). This dynamic behaviour is known as
runtime polymorphism.

Note 1:
• Overload resolution takes place entirely at compile time.
• You cannot overload methods with the methods differing in return types
alone.

Prepared by Prophet Zanamwe N @2014


• You cannot overload methods with the methods differing in exception
specifications alone.
• For overload resolution to succeed, you need to define methods such that
the compiler finds one exact match. If the compiler finds no matches for
your call or if the matching is ambiguous, the overload resolution fails and
the compiler issues an error.

The is-a principle states that objects of a subclass are also members(objects) of the supper
class, by definition. Accordingly, we can always assign an object of the subclass to a
variable of the super class hence, object variables in Java are polymorphic. No explicit
cast is required because the relationship is implicit in the inheritance hierarchy. For
example, if class Manager extends class Employee then an Employee variable can store
an Employee object or a Manager object. If a method is invoked on a superclass variable,
the system determines which class of object the variable actually contains and calls the
appropriate method for objects of that class:

Employee e1 = new Employee(“Makanyara Gora”, 3000, 2000, 12, 01);


Employee e2 = new Employee(“Muchaneta Dombo”, 4567, 2003, 11, 20);
Manager m1 = new Manager (“Tichafa Mboko”, 56789, 2002, 09, 12, “Maidei Vera”);
Manager m2 = new Manager (“Tofirei Musa”, 76789, 2006, 09, 12, “Kurai Choto”);

Employee[] staff = new Employee[4];


staff[0] = e1;
staff[1] = e2;
staff[3] = m1;
staff[4] = m2;

for(int i = 0; i < staff.length; i++)


{
staff[i].print();

the system automatically selects the correct print() method for either Employee or
Manager objects. The system selects the appropriate method to use at run-time, not at
compile-time:

Employee e;
System.out.print(“Store e1 or m1 in e ?”);
String answer = in.readLine();
if (answer.equals(“e1”))
{
e = e1;

Prepared by Prophet Zanamwe N @2014


else
{
e = m1;
}
e.print();

the automatic selection of the appropriate method to apply to objects in an inheritance


hierarchy is termed dynamic binding, and we can describe the print() method of ,the
superclass as polymorphic. Polymorphism refers to the fact that a super class variable can
refer to multiple actual types e.g. e (an Employee type) can refer to employee and
manager objects.

Java implements polymorphism by binding identifiers to their references at run-time,


termed dynamic or late binding. Polymorphism makes it easy to extend a program: the
superclass Employee can be extended to Supervisor and Administrator classes, for
example, each with their own print() or whatever methods, without having to modify the
existing code for the superclass methods.

True polymorphism can be distinguished from simple overloading where several methods
with the same name are distinguished by having different argument lists. Overloading,
termed ad hoc polymorphism is implemented using static binding at compile time. For
example, the constructors Employee() and Employee(String name, double salary)
overload the name Employee. Calls to these methods are easily distinguished at compile
time by simply matching the parameter list of the caller and the method.

Note 2:
The overriding method
• Should have the same argument list types (or compatible types) as the base
version.
• Should have the same return type.
• But from Java 5 onwards, the return type can be a subclass–covariant return types.
• Should not have a more restrictive access modifier than the base version.
o But it may have a less restrictive access modifier.
• Should not throw new or broader checked exceptions.
o But it may throw fewer or narrower checked exceptions, or any unchecked
exception.
• The names should exactly match

Remember that you cannot override a method if you do not inherit it. Private methods
cannot be overridden because they are not inherited.

If the name or signature of the base class method and the overriding method don’t match,
you will cause subtle bugs. So ensure that they are exactly the same.

In order to overcome the subtle problems of overloading, you can use @Override
annotation, which was introduced in Java 5. This annotation explicitly expresses to the

Prepared by Prophet Zanamwe N @2014


Java compiler the intention of the programmer to use method overriding. In case the
compiler is not satisfied with your overridden method, it will issue a complaint, which is
a useful alarm for you. Also, the annotation makes the program more understandable,
since the @Override annotation just before a method definition helps you understand that
you are overriding a method.

The JVM keeps track of the actual class of objects stored in object variables in order to
implement polymorphism. The actual class name is accessible to the programmer using
the getClass().getName() method.

Note that if you have:


Manager m1 = new Manager(...);
Employee[] staff = new Employee[3];
staff[0] = m1;

both staff[0] and m1 refer to the same object but staff[0] is considered to be only an
employee object by the compiler. This means that you can call

m1.getSecretaryName(); // ok

but you can’t call

staff[0].getSecretaryName();// error

The declared type of staff[0] is Employee and the getSecretaryName() method is not a
method of the Employee class. Take note that the getSecretaryName() method is not
defined in the super class.

Arrays of subclass references can be converted to arrays of superclass references without


a cast eg

Manager[] managers = new Manager[10];

It is proper to convert this array to an Employee[] array:

Employee[] staff = managers;

But be careful with arrays because one can say:

staff[0] = new Employee()

such that staff[0] and managers[0] are the same reference. Can we call

managers[0].getSecretaryName();

Which will try to access a nonexistent field which would corrupt neighbouring memory.

Prepared by Prophet Zanamwe N @2014


To ensure that no corruption occurs all arrays remember the element type with which
they were created and they monitor that only compatible references are stored into them
eg trying to store employee references in a manager array generates an
ArrayStoreException

Access Modifiers/Specifiers
Access modifiers determine the level of visibility (and therefore access) for a Java entity
(a class, method, or field).

Access modifiers enable you to enforce effective encapsulation. If all member variables
of a class can be accessed from anywhere, then there is no point putting these variables in
a class and no purpose in encapsulating data and methods together in a class.

Java supports four types of access modifiers:


• Public
• Private
• Protected
• Default (no access modifier specified)

Public Access Modifier


The public access modifier is the most liberal one. If a class or its members are declared
as public, they can be accessed from any other class regardless of the package boundary.
It is comparable to a public place in the real world, such as a company cafeteria that all
employees can use irrespective of their department.

Private Access Modifier


The private access modifier is the most stringent access modifier. A private class member
cannot be accessed from outside the class; only members of the same class can access
these private members. It’s comparable to a safe deposit box room in a bank, which can
only be accessed by a set of authorized personnel and safe deposit box owners.

State/Data should always be private because:


1. Some values may be read only once they are set by the constructor and there will
be guarantee that they will not be changed.
2. For instance variables with mutator methods if something goes wrong you simply
debug the method and also methods can perform error checking unlike public
instance variables
3. You can also change the implementation without changing the data field.

Private methods are desirable where you wish to break up the code for a computation into
separate helper methods.

Protected Access Modifier

Prepared by Prophet Zanamwe N @2014


Data and methods which are declared public can be accessed by any other class including
any subclasses. If, they are declared private to a class then other classes can only access
them using the public interface provided.

Java also provides the protected access modifier: protected data or methods in a class can
be accessed by subclasses. Any class that extends a class with protected data or methods
can access the data and methods as though they were public. Although this is seemingly
an attractive idea, in practice this is problematic because once protected access provided
it cannot be easily withdrawn because users may write subclasses whose code depends on
this access. It is always a bad idea to give class data protected access because this breaks
encapsulation and you cannot change the implementation later in case the class has been
extended and the protected data accessed by new subclasses. Rather provide an accessor
method and give this protected access to preserve encapsulation.

Default Access Modifier


Default access modifiers are quite similar to protected access modifiers. If a member
method or field is declared as default, then the method or field can be accessed within the
package. Note that there is no explicit keyword to provide default access—in fact, when
no access modifier is specified, the member has default access. Also, note that default
access is also known as package-protected access. Protected and default accesses are
comparable to the situation in an office where a conference room is accessible only to
one department.

What is the difference between protected and default access? One significant difference
between these two access modifiers arises when we talk about a subclass belonging to
another package than its superclass. In this case, protected members are accessible in the
subclass, whereas default members are not.

For example, if salary data for Employee is declared as protected it is accessible in all its
subclasses like Manager. If Manager belongs to yet another package, all the protected
methods and data will be accessible but data and methods with default access specifier
are not accessible in other packages.

Final access
We can prevent users from deriving subclasses from existing classes by declaring them as
final (eg public final class Employee). We can also make a specific method in a class
final so that no other method can override it. All methods of a final class are
automatically final.

Programs which attempt to extend final classes compile but will fail at run-time.

Classes and methods are made final for two reasons:

Prepared by Prophet Zanamwe N @2014


1. Efficiency: the compiler can then arrange for static binding which is more
efficient than dynamic binding and it can replace trivial method calls with inline
code like replacing e.getName() with e.name;
2. Safety: when you send a message like e.getName() e may be an object of a
derived class which redefines the getName() method to return a completely
different string; making getName() final avoids this ambiguity.

Many Java system classes are final, for example class String and the wrapper classes
(Integer, Double and Boolean)

Final instance variables or fields cannot be changed after initialised when object is
constructed eg private final String name; they are useful for fields whose type is primitive
or an immutable class.

Note that when a class is declared as final, only methods not fields are automatically
final.

Access Modifiers and Their Visibility

It is important to note that a class (or interface) cannot be declared as private or protected.
Furthermore, member methods or fields of an interface cannot be declared as private or
protected.

Static fields and methods

Static fields are called class variables or fields and there is only one such field per class.
Are declared as: private static int number; static variables are rare but
static constants are common eg PI in the Math class:
public static final PI=3.14159265389...
and is accessed as Math.PI

static methods do not operate on objects eg pow() in the Math class is a static method.
Because static methods don’t operate on objects, you cannot access instance fields from
static methods. But static methods can access the static fields in their class here is an
example of such a static method:
public static int getNextId()
{
return nextID // returns a static field

Prepared by Prophet Zanamwe N @2014


To call this method you supply the name of the class:
int n = Employee.getNextId();

Prepared by Prophet Zanamwe N @2014

You might also like