You are on page 1of 12

8966474.

doc FBE – Computer Science Dept

Mekelle University Faculty of Business & Economics

Computer Science Department

Comp 262: Internet Programming with Java

Handout 5 – Classes and Inheritance

Reference:
You may find it useful to look at the Java tutorial, taken from the Sun Java website, on
the intranet – browse to Computers, Course Materials and look under the heading for
this course.

1 Overview
This handout covers in greater depth the OO concept of inheritance and how it is used
in Java. Abstract classes and interfaces, and their uses, are discussed.

2 Extending a class (inheritance)


Code Example: Demos/People
Inheritance is one of the key principles of OO programming. It allows a class to get,
or reuse, the data members and methods of another class.
2.1 Extends Keyword
In Java, the keyword used to indicate inheritance is extends. For example, to declare a
class named Employee that inherits from a class named Person:

class Employee extends Person

Note that this is like using the colon (:) in C++.


When class B extends class A, class B automatically inherits all fields and methods
from class A. This includes instance and class fields and methods. Class A is called a
super class (also known as a base or parent class). Class B is the subclass (also known
as a derived or child class).

A subclass automatically inherits data and methods from its super class. These are as
follows:

• Super class members declared as public or protected – this includes


data (variables) and methods, both class and instance.
• Super class members declared with no access specifier as long as the
subclass is in the same package as the superclass, including both class
and instance (a package is a group of related classes grouped together
using the package directive – we will discuss packages further at a later
stage)

A class that is declared as final cannot be extended. A final class should be used where
the class defines functionality that should not be changed in the program or any
programs using it. For example:

Page 1 of 12
8966474.doc FBE – Computer Science Dept

final class someClass { }


2.2 Hiding Member Variables
If the subclass declares a variable with the same name as a variable in the super class,
we say that the subclass hides the super class variable.

For example:
class SuperClass {
int x;
}

class SubClass extends SuperClass {


float x;
}

The float variable x hides the int variable x. If x is accessed in the class SubClass, it is
accessing the float variable. However, the int variable x can be accessed using the
super keyword. Super refers to the super class. Another keyword, this can be used to
access the x variable in the subclass – this is the same as just accessing x, but it makes
it clear which x is being accessed.

x //refers to the float variable x


this.x //refers to the float variable x
super.x //refers to the int variable x

In practice, it is rare to hide a super class variable – it is more likely that the variable
in the subclass represents a different data member of the class, so it should have a
different name.
2.3 Overriding Super Class Methods

If the subclass declares a method with the same name, return type and parameter list
(this is also known as the signature of the method) as a method in the super class, the
subclass does not inherit the method from the super class. We say that the subclass
overrides the method.

When the method is invoked for objects of that class, the interpreter calls the new
definition of the method, not the super class's definition of the method.

Note that if the subclass declares a method with the same name but with a different
parameter list, then it is not overriding the method in the super class. It is overloading
the method. An overloaded method can also appear in the same class i.e. two methods
with the same name but with different parameter lists can appear in the same class. At
runtime, the interpreter determines which method to call based on the parameter list.

The keyword super can be used to invoke the method of the super class. This is often
used because the overriding method in the subclass is simple adding more
functionality to the method in the super class. Consider the following classes, showing
a simple initial implementation of the Person and Employee classes (as depicted in
Figure 5, on page 7 of Handout 1). The getDetails() method of the Person super class
is overridden in the Employee class. It makes a call to the super class method to avoid
duplicating the code to get the name, address and date of birth instance variable
values.
Page 2 of 12
8966474.doc FBE – Computer Science Dept

import java.util.Date;

class Person {

protected String name;


protected String address;
protected Date dateOfBirth;

//other class code omitted


/**
Return a string showing the details for this Person object
*/
public String getDetails () {

return name + "\n" + address + "\n" + dateOfBirth;


}
}

public class Employee extends Person {

protected long salary;


protected String department;
protected String rank;

//other class code omitted


/**
Return a string showing the details for this Employee object.
First call the getDetails() method in the super class, Person, to get
the details from that class.
*/
public String getDetails () {
return super.getDetails() + "\nSalary: " + salary +
"\nDepartment: " + department + "\nRank: " + rank;

}
}

The subclass method that overrides a method in the super class must have the same
return type – if it does not, the compiler will report an error. This makes sense,
because if the overriding method needs to return a different data type, then it is likely
that the method is actually performing a different function, so it should have a
different name.

There are some cases where a method cannot be overridden.


• A subclass cannot override a method that is declared as final in the super class.
The final keyword means that the method definition is final and cannot be
changed. Using the final keyword allows the compiler to make some
optimisations when invoking class methods. A method that carries out
functionality that does not change should be declared final.
• A subclass cannot override a method that is declared as static in the super
class. Remember that static methods are class methods i.e. they are accessed
using the class name, not an instance/object name. They can be hidden, in the

Page 3 of 12
8966474.doc FBE – Computer Science Dept

same way that instance variables can be hidden – by declaring a static method
in the subclass, with the same name and signature as the super class method.

3 Access Modifiers
We have seen various access modifiers being used in the classes we have worked with
so far. It is important to be aware of the meanings of these modifiers. As mentioned
above, they impact what a subclass can inherit from super classes.

Public
A public variable or method is accessible to all other classes and subclasses.

Package
Package access is also known as ‘friendly’ access. A class can be assigned to be part
of a package. Usually, a group of related classes are assigned to the same package. In
Java itself, for example, all IO classes are in the java.io package.
If no access modifier is specified for a variable or method, it is accessible only to
other classes and subclasses that are in the same package.

Protected
A protected variable or method is accessible to classes and subclasses in the same
package and also to subclasses in other packages. The visibility level of a protected
member is between the levels of public and package access.

Private
A private variable or method is accessible only within the class in which it is declared.
It is not accessible to subclasses. In other words, a private variable or method is not
inherited by subclasses.

A class itself can be declared as public, but cannot be declared as private or protected.
If a class has no access modifier specified, it is accessible only in its own package.
A class that is declared public is accessible anywhere its package is accessible.

The visibility of class members for the different access modifiers are summarised in
the table below.

Access modifier
Accessible to Public Protected Package (friendly) Private
Same class Yes Yes Yes Yes
Subclass in same Yes Yes Yes No
package
Other classes in Yes Yes Yes No
same package
Subclass in other Yes Yes No No
package
Non-subclass in Yes No No No
other package

The programmer should use the access modifiers to protect the data inside a class,
thus applying the OO concept of data encapsulation. Guidelines for deciding what
access modifiers to use are as follows:

Page 4 of 12
8966474.doc FBE – Computer Science Dept

• Use public only for methods and constants (not variables) that form part of the
public API1 (Application Programming Interface) of the class. If there are
member variables that are important or frequently used, they can be public -
but it is more common and good practice to make all fields non-public and
encapsulate them with public accessor methods (e.g. public String getName(),
public String getAddress()). Public members should be documented so that the
API informs other programmers about them. Remember that if changes are
made to anything that is part of the API of a program, they can potentially
break code that relies on the API.
• Use protected for variables and methods that are not required by most
programmers using the class, but that may be of interest to anyone creating
subclass as part of a different package. Protected members are technically part
of the API of a class – so they should be documented and changes may break
other code relying on the API.
• Use the default package visibility for variables and methods that are internal
implementation details, but may be used by cooperating classes in the same
package. To do this, you need to use the package directive at the top of a class.
• Use private for variables and methods that are used only inside the class and
should be hidden everywhere else.

4 Constructor chaining & default constructor


4.1 Inheritance Hierarchy
More than two sub-classes can inherit from the same super class. A subclass can itself
be a super class to other subclasses. The classes then form an inheritance hierarchy.

It is important to be aware of how the Java compiler and interpreter deal with an
inheritance hierarchy. We have already discussed how methods can be overridden and
how member variables can be hidden.
Inheritance also has implications for the constructors of an object.

4.2 Constructor Chaining


The constructor of a class is called whenever an object of that class is instantiated.
The constructor is also called when an instance of any subclass of that class is
instantiated.
For example, when an Employee object is instantiated, the constructor for the super
class Parent is called.
The constructor of the subclass is also called. The constructor of the super class is
called first. It is possible to define a class without a constructor, but in this case the
Java compiler implicitly adds an empty constructor to the class – so, strictly speaking,
all classes have a constructor. The default constructor is one that takes no parameters.

If the subclass constructor does not explicitly call the constructor of the super class,
the Java compiler automatically inserts a call to the default constructor of the super
class (the default constructor is the one that takes no parameters).
Alternatively, the programmer can do this explicitly in the code by using the super()
keyword i.e.
1
API: Application Programming Interface. This is a general programming term that refers to those
parts of a program that are exposed for use by other programs and programmers. An API often also
includes the documentation about the program. For Java, this means the JavaDoc documentation about
the classes in the program.

Page 5 of 12
8966474.doc FBE – Computer Science Dept

super() //calls the constructor of the super class

If the super class has a constructor that takes parameters, it must be explicitly called
by the programmer e.g.

super(arg1, arg2) //calls the constructor of the super class

If the call to the super class constructor has the wrong number of type of parameters,
the compiler will report an error.

In the same way that an overriding method in a subclass often just adds functionality
to the method in the super class, the constructor in a subclass may just add more steps
to the super class constructor.
Consider the Person and Employee classes again. The Person class might have a
constructor like this:

/**
Constructor
*/
public Person (String firstName, String fathersName, String address,
Date dateOfBirth)
{
name = firstName + " " + fathersName;
this.address = address;
this.dateOfBirth = dateOfBirth;

Note the use of the this keyword – this accesses a variable whose scope is the object
or instance. If the line 'this.address = address' were to read 'address = address' , it
would only be setting the parameter variable address to be its own value, it would not
be setting the address instance variable. The this keyword cannot be used in class
methods (declared using the static keyword) – because class methods are not
associated with instances, only with the class.

The constructor for the Employee class would need to pass the name, address and date
of birth values to the super class, and also set its own instance variables. So it might
be like this:

/**
Constructor
*/

public Employee (String firstName, String fathersName, String


address, Date dateOfBirth, long salary, String dept, String rank)
{
//pass values to the constructor of the super class Person
super(firstName, fathersName, address, dateOfBirth);
this.salary = salary;
department = dept;
this.rank = rank;

Page 6 of 12
8966474.doc FBE – Computer Science Dept

It is better to explicitly call the super class constructor, even it has no parameters (i.e.
the call is just super()) as this makes it clear to another programmer that there is a
super class involved.

4.3 Calling a different Constructor in the Same Class


Sometimes, there may be different constructors for the same class. Constructors are
differentiated by taking different parameter lists – a parameter list is different if one or
more of the data types are different and/or if the number of parameters is different.
The interpreter determines which constructor to call based on the number and types of
the parameters being passed.
For example, if the rank of an Employee is not known, it may not be passed in the
constructor. In this case, rather than duplicating the code in the first constructor, we
can just use this() to call the first constructor, and pass it a value of null for the rank.

/**
Constructor to use when rank is not available (default to null)
*/
public Employee (String firstName, String fathersName, String
address, Date dateOfBirth,
long salary, String dept)

{
//call the main constructor, giving NULL as the rank
this (firstName, fathersName, address, dateOfBirth, salary,
dept, null);
}

5 Abstract Classes
In Handout 1, the idea of an abstract class was mentioned. An abstract class is a class
from which objects cannot be instantiated.
To make a Java class abstract, the class must be declared using the abstract keyword.
For example, if we want to ensure that a Person object is never instantiated, because a
person must be an Employee (or some other, as yet undefined, subclass of Person), we
can declare it like this:

abstract class Person {


//class body omitted
}

The keyword abstract appears before the class keyword, but after the access modifier
for the class (if any).

Methods can also be declared as abstract. An abstract method does not have a body
i.e. it has no statements. It only declares the method name, access modifier, return
type and parameters. The method must have a semi-colon to indicate the empty body.
All subclasses must define an implementation of the abstract method.

Consider a program that defines classes for different shapes. All the shapes might
have a common super class named Shape. It does not make sense to instantiate an

Page 7 of 12
8966474.doc FBE – Computer Science Dept

object of type Shape, as it must be a circle or a triangle or a square etc. So the Shape
class would be abstract. If we want to ensure that all subclasses implement methods to
calculate the area and the circumference of the shape, we can add abstract methods to
the Shape class.

public abstract class Shape {


public abstract double area();
public abstract double circumference();
}

Any subclass of Shape must now provide its own implementation of the area and
circumference methods.

public class Circle extends Shape


{

protected double radius;

/**
* Constructor for objects of class Circle
*/
public Circle(double a_Radius)
{

radius = a_Radius;
}

public double calcArea()


{
return (Math.PI * radius * radius);
}

public double circumference()


{
return (2 * Math.PI * radius);
}
}

Some other points about abstract classes:

• If a class has one or more abstract methods, the class itself must be declared as
abstract.
• Static, private and final methods cannot be abstract – because these types of
method cannot be overridden by subclasses.
• A final class cannot have any abstract methods.
• If a subclass of an abstract class does not implement all the abstract methods it
inherits, then that class is itself abstract.
• Objects of a subclass can only be instantiated if the subclass overrides all of
the abstract methods of the super class and provides an implementation (a
method body) for all of them. This is a concrete class.
• An abstract class can have non-abstract methods. These methods do not have
to be overridden by subclasses, but they can be if necessary.

Page 8 of 12
8966474.doc FBE – Computer Science Dept

5.1 Using Abstract Classes


Code Example: Demos/Shapes (BlueJ project)
To illustrate the convenience of abstract classes and methods, look at the Shapes
example (code in Code Examples\Shapes). The class TestShapes creates an array of
different shape objects. The array is defined as an array of Shape objects. Because
Circle and Square are subclasses of Shape, they can be placed in the array.

This holds for any variable – a variable can hold objects of the declared type of the
variable (e.g. Shape ) or of any subtype of the declared type (e.g. Circle, Square).
Here, the class is the type of the variable and subtype objects may be used wherever
objects of a super type are expected. This is known as substitution (because the
subtype can be substituted for the super type) and is similar to a widening conversion
between primitive data types e.g. a short literal value can be assigned to an int
variable.

The code iterates through the shapes array and prints out the area of each element, by
calling the area() method of each Shape object. The area() method for the Shape class
does not have an implementation, but the interpreter determines which area method to
invoke by checking the type of the object at the current element in the array. This is
the OO concept of dynamic (late) binding.
To see why the area() method must be declared in the super class as well as in the
subclasses, take the Shape class and comment out the line that declares the area()
method, compile the class and then try to compile TestShapes. The compiler will
report an error like 'cannot resolve symbol' for 'method area()'.

public class TestShapes


{

public static void main (String[] args)


{
//create an array of shapes
Shape[] shapes = new Shape[3];

shapes[0] = new Circle (3.0);


shapes[1] = new Square (3.0);
shapes[2] = new Rectangle (2.0, 3.0);

//get area of each shape


for (int i=0; i<shapes.length ; i++)
{
System.out.println ("Area of shape at element " + i + "
is:" + shapes[i].area());
}

Casting Objects
In the above example, the placing of a Circle object in an array of shapes was
effectively a widening conversion.

Page 9 of 12
8966474.doc FBE – Computer Science Dept

If we want to take an object from the array and work with it, we may want to assign it
to a variable of type Circle. For example, add the following code into the TestShapes
class, in the main method and try to compile:

Circle c;
c = shapes[0];

The compiler will report an 'incompatible types' error, stating 'found: Shape; required:
Circle'. This is because an object of a super class of Circle, the type for c, cannot be
assigned to c. A cast is necessary i.e.

Circle c;
c = (Circle) shapes[0];

This is similar to a narrowing conversion, because the object in the array is being
converted from a Shape to a Circle i.e. from the super class to the subclass.

6 Interfaces
Java allows a class to inherit from one other class only i.e. a class can have only one
super class. However, there may be cases where it is necessary for a class to inherit
from more than one source. The Java solution to this problem is interfaces.
A class can implement one or more interfaces. An interface is a reference data type
that is very similar to a class.

For example, in the Shapes example used above, if a shape can be centred on a given
point, the shape would need to inherit from the normal (non-centred) class for that
shape. E.g., a CentredCircle class would inherit from Circle. But it would also need to
inherit methods to set the centre point and to get the coordinates of the centre.
Not all shapes are centred, so it is not ideal to put the centre point methods in the
Shape super class. So we can instead put the methods in an interface.

public interface Centred

{
public void setCentre(double x, double y);
public double getCentreX();
public double getCentreY();
}

Note that the interface can only have abstract methods – it cannot implement the
methods.
A subclass of the Circle class can now also implement this interface. A class that
implements an interface must implement the methods in the interface.

public class CentredCircle extends Circle implements Centred


{

//add instance fields for the centre point


private double cx, cy;

/**
* Constructor for objects of class CentredCircle

Page 10 of 12
8966474.doc FBE – Computer Science Dept

*/
public CentredCircle(double cx, double cy, double a_Radius)
{

super (a_Radius);
this.cx = cx;
this.cy = cy;
}

//implement the abstract methods in the Centred interface


public void setCentre (double x, double y) { cx = x; cy = y;}

public double getCentreX() { return cx;}


public double getCentreY() { return cy;}

Some points about interfaces:


• An interface does not provide any implementations - because, as the name
suggests, it supplies an interface, or API, for certain functionality.
• An interface is similar to a class, but not the same as a class. It can contain
methods and variables, like a class. But, an interface can define only abstract
methods (i.e. no implementation) and final fields (constants).
• An interface can declare only abstract methods, so the methods have no
implementation. All interface methods are instance methods – they cannot be
class methods because class methods cannot be abstract.
• All methods in an interface are implicitly public - because an interface defines
a public API
• An interface cannot define instance variables (fields). A field is an
implementation detail, while an interface is supposed to be an API, without
any implementation. Hence, the only fields that can be defined in an interface
are constants, and they must be declared as static and final.
• Interfaces are often used to define large numbers of constants used by various
classes in a program. This is similar to creating header files in C++ to contain
a large number of constants. Any class that implements the interface inherits
the constants in the interface; it is not necessary to prefix the constant names
with the interface name.

Like a class, an interface is a reference data type. Therefore, when a class implements
an interface, instances of that class can be assigned to variables of the interface type.
For example, see the class TestShapesInterface. This creates an array of shape objects
and then iterates through the array to write out the area of each shape. It also tests
each shape to see if it is also a Centred shape. If it is, the centre point is also written
out.

public class TestShapesInterface


{

public static void main (String[] args)


{

Page 11 of 12
8966474.doc FBE – Computer Science Dept

//create an array of shapes


Shape[] shapes = new Shape[3];

//add some shapes


/*Exercise:
* create new classes CentredSquare & CentredRectangle, and
replace shapes[1] and shapes[2]
* below with instances of each of these.
* */
shapes[0] = new CentredCircle (1.0,1.0,1.0);
shapes[1] = new Circle (3.0);
shapes[2] = new CentredCircle (2.3,4.5,3.4);

//get area of each shape


for (int i=0; i<shapes.length ; i++)
{
System.out.println ("\nArea of shape at element " + i +
" is:" + shapes[i].area());
//if it is a Centred shape, also print out the centre
point coordinates
//use instanceof operator to check if it is an instance
of the Centred interface
if (shapes[i] instanceof Centred) {
Centred c = (Centred) shapes[i]; //have to cast to
Centred - see what happens if you do not include the cast
System.out.println ("Centre point is (" +
c.getCentreX() + "," + c.getCentreY() + ")");
}
else
{
System.out.println ("Not a centred shape");
}

Notes prepared by: FBE Computer Science Department.

Page 12 of 12

You might also like