0% found this document useful (0 votes)
264 views20 pages

Object-Oriented Programming Principles

The document discusses three key object-oriented programming principles: encapsulation, inheritance, and polymorphism. It defines encapsulation as binding code and data together to keep them safe from outside interference. Inheritance allows new classes to inherit and extend the functionality of existing classes. Polymorphism refers to the ability of objects with different internal structures to respond to the same method call. The document provides examples in Java code to illustrate encapsulation using private variables and public getters/setters, as well as inheritance where a Triangle class extends a TwoDShape class.

Uploaded by

abibual desalegn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
264 views20 pages

Object-Oriented Programming Principles

The document discusses three key object-oriented programming principles: encapsulation, inheritance, and polymorphism. It defines encapsulation as binding code and data together to keep them safe from outside interference. Inheritance allows new classes to inherit and extend the functionality of existing classes. Polymorphism refers to the ability of objects with different internal structures to respond to the same method call. The document provides examples in Java code to illustrate encapsulation using private variables and public getters/setters, as well as inheritance where a Triangle class extends a TwoDShape class.

Uploaded by

abibual desalegn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

OOP: Chapter 3- Object Oriented Principles

1. Introduction
Chapter 2 introduced you to classes and objects. In this chapter, you learn about the fundamental
concepts of object-oriented programming. The three major principles that make a language object-
oriented are: Encapsulation, Inheritance and Polymorphism. The main purpose of these principles
is to manage software system complexity by improving software quality factors.

2. Encapsulation
Encapsulation is a programming mechanism that binds together code and the data it manipulates,
and that keeps both safe from outside interference and misuse. It refers to the combining of fields
and methods together in a class such that the methods operate on the data, as opposed to users of
the class accessing the fields directly. It is a technique which involves making the fields in a class
private and providing access to the fields via public methods. We can use setter and getter methods
to set and get the data in it.
We can create a fully encapsulated class in java by making all the data members of the class private.
The whole idea behind encapsulation is to hide the implementation details from users. If a data
member is private it means it can only be accessed within the same class. No outside class can
access private data member (variable) of other class. Encapsulation can be described as a protective
barrier that prevents the code and data being randomly accessed by other code defined outside the
class. The main benefit of encapsulation is the ability to modify our implemented code without
breaking the code of others who use our code.
To implement encapsulation in java:
a. Make the instance variables private so that they cannot be accessed directly from outside
the class. You can only set and get values of these variables through the methods of the
class.
b. Have getter and setter methods in the class to set and get the values of the fields.
class EncapsulationDemo{
private int empId;
private String empName;
private int empAge;

//Getter and Setter methods


public int getEmpId(){
return empId;
}
public String getEmpName(){
return empName;
}
public int getEmpAge(){
return empAge;
}
public void setEmpAge(int newValue){
empAge = newValue;
}

public void setEmpName(String newValue){


empName = newValue;
}

University of Gondar, Department of Computer Scienc Page 1


OOP: Chapter 3- Object Oriented Principles

public void setEmpId(int newValue){


empId = newValue;
}
} Program Output
public class EncapsTest{
public static void main(String args[]){
EncapsulationDemo obj = new EncapsulationDemo(); Employee Name: Aregahegn
obj.setEmpName("Aregahegn"); Employee ID: 1125
obj.setEmpAge(24); Employee Age: 24
obj.setEmpId(1125);
System.out.println("Employee Name: " + obj.getEmpName());
System.out.println("Employee ID: " + obj.getEmpId());
System.out.println("Employee Age: " + obj.getEmpAge());
}
}
Encapsulation provides you the control over the data. Suppose you want to set the value of
empId i.e. greater than 100 only, you can write the logic inside the setter method.

Data Abstraction
The client cares about what functionality a class offers, not about how that functionality is
implemented. This concept referred to as data abstraction. Data abstraction is the separation of
class implementation from the use of a class. For example, you can create a Circle object and find
the area of the circle without knowing how the area is computed. The details of implementation
are encapsulated and hidden from the user. Data abstraction and encapsulation are two sides of the
same coin.

3. Inheritance
3.1.What is Inheritance?
In the real world: We inherit traits from our mother and father. We also inherit traits from our
grandmother, grandfather, and ancestors. We might have similar eyes, the same smile, a different
height . . . but we are in many ways "derived" from our parents.
In software: Object inheritance is more well defined! Objects that are derived from other object
"resemble" their parents by inheriting both state (fields) and behavior (methods).

Object-oriented programming allows you to derive new classes from existing classes. This is called
inheritance. Inheritance is an important and powerful concept in Java. In fact, every class you
define in Java is inherited from an existing class, either explicitly or implicitly. The classes you
created in the preceding chapters were all extended implicitly from the java.lang.Object class.
This section introduces the concept of inheritance.

The process by which one class acquires the properties (data members) and functionalities
(methods) of another class is called inheritance. The aim of inheritance is to provide the
reusability of code so that a class has to write only the unique features and rest of the common
properties and functionalities can be extended from the another class.

The idea behind inheritance is that you can create new classes that are built on existing classes.
When you inherit from an existing class, you reuse (or inherit) its methods and fields and you add
new methods and fields to adapt your new class to new situations. This technique is essential in
Java programming.

University of Gondar, Department of Computer Scienc Page 2


OOP: Chapter 3- Object Oriented Principles

3.2.Superclasses and Subclasses


In Java terminology, a class C1 extended from another class C2 is called a subclass, and C2 is
called a superclass. A superclass is also referred to as a supertype, a parent class, or a base class,
and a subclass as a subtype, a child class, an extended class, or a derived class. A subclass inherits
accessible data fields and methods from its superclass, and may also add new data fields and
methods.

Contrary to the conventional interpretation, a subclass is not a subset of its superclass. In fact, a
subclass usually contains more information and functions than its superclass.
Note
Inheritance is used to model the is-a relationship. Do not blindly extend a class just for the sake of
reusing methods. For example, it makes no sense for a Tree class to extend a Person class. A
subclass and its superclass must have the is-a relationship.
3.3.Member Access and Inheritance
The visibility of an element is determined by its access specification: private, public, protected,
or default, and the package in which it resides. As you learned in chapter 2, often an instance
variable of a class will be declared private to prevent its unauthorized use or tampering. Inheriting
a class does not overrule the private access restriction. Thus, even though a subclass includes all
of the members of its superclass, it cannot access those members of the superclass that have been
declared private.

If a member of a class has no explicit access specifier, then it is visible within its package but not
outside its package. Therefore, you will use the default access specification for elements that you
want to keep private to a package but public within that package.

Members explicitly declared public are visible everywhere, including different classes and
different packages. There is no restriction on their use or access. A member specified as protected
is accessible within its package and to all subclasses, including subclasses in other packages.
Syntax: Inheritance in Java
Java supports inheritance by allowing one class to incorporate another class into its declaration.
This is done by using the extends keyword. Thus, the subclass adds to (extends) the superclass.
Consider the following:
class XYZ extends ABC
{
}
Here class XYZ is child class and class ABC is parent class. The class XYZ is inheriting the
properties and methods of ABC class.
Inheritance Example
// A class for two-dimensional objects.
class TwoDShape {
double width;
double height;
void showDim() {
System.out.println("Width and height are " + width + " and " + height);
}
}
// A subclass of TwoDShape for triangles.

University of Gondar, Department of Computer Scienc Page 3


OOP: Chapter 3- Object Oriented Principles

class Triangle extends TwoDShape {


String style;
double area() {
return width * height / 2;
}

void showStyle() {
System.out.println("Triangle is " + style);

}
}
public class Shapes {
public static void main(String args[]) {
Triangle t1 = new Triangle();
Triangle t2 = new Triangle();
t1.width = 4.0;
t1.height = 4.0;
t1.style = "isosceles"; Program Output
t2.width = 6.0;
t2.height = 8.0; Info for t1:
t2.style = "right"; Triangle is isosceles
System.out.println("Info for t1: "); Width and height are 4.0 and 4.0
t1.showStyle(); Area is 8.0
t1.showDim();
System.out.println("Area is " + t1.area()); Info for t2:
System.out.println(); Triangle is right
System.out.println("Info for t2: "); Width and height are 6.0 and 8.0
t2.showStyle(); Area is 24.0
t2.showDim();
System.out.println("Area is " + t2.area());
}
}

The instanceof Keyword


The instanceof operator compares an object to a specified type. Let us use the instanceof operator to check
whether Triangle is actually a TwoDShape.
System.out.println(t1 instanceof TwoDShape); //displays true

3.4.The super Keyword


A subclass inherits accessible data fields and methods from its superclass. Does it inherit
constructors? Can superclass constructors be invoked from subclasses? The keyword super refers
to the superclass of the class in which super appears. It can be used in two ways:
 To call a superclass constructor.
 To access a superclass members.
a. Calling Superclass Constructors

The syntax to call a superclass constructor is: super(), or super(parameters); The statement
super() invokes the no-arg constructor of its superclass, and the statement super(arguments)
invokes the superclass constructor that matches the arguments. The statement super() or
super(arguments) must appear in the first line of the subclass constructor and is the only way to
invoke a superclass constructor.

University of Gondar, Department of Computer Scienc Page 4


OOP: Chapter 3- Object Oriented Principles

To see how super( ) is used, consider the version of TwoDShape in the following program. It
defines a constructor that initializes width and height.
// Add constructors to TwoDShape.
class TwoDShape {
private double width; // these are
private double height; // now private
// Parameterized constructor.
TwoDShape(double w, double h) {
width = w;
height = h;
}
// Accessor methods for width and height.
double getWidth() { return width; }
double getHeight() { return height; }
void setWidth(double w) { width = w; }
void setHeight(double h) { height = h; }
void showDim() {
System.out.println("Width and height are " +
width + " and " + height);
}
}
// A subclass of TwoDShape for triangles.
class Triangle extends TwoDShape {
private String style;
Triangle(String s, double w, double h) {
super(w, h); // call superclass constructor

style = s;
}
double area() {
return getWidth() * getHeight() / 2;
}
void showStyle() {
System.out.println("Triangle is " + style);
}
}
public class Shapes2 {
public static void main(String args[]) {
Triangle t1 = new Triangle("isosceles", 4.0, 4.0);
Triangle t2 = new Triangle("right", 6.0, 8.0);
System.out.println("Info for t1: ");
t1.showStyle();
t1.showDim();
System.out.println("Area is " + t1.area());
System.out.println();
System.out.println("Info for t2: ");
t2.showStyle();
t2.showDim();
System.out.println("Area is " + t2.area());
}
}
Here, Triangle( ) calls super( ) with the parameters w and h. This causes the TwoDShape( )
constructor to be called, which initializes width and height using these values. Triangle no longer
initializes these values itself. It need only initialize the value unique to it: style. This leaves
TwoDShape free to construct its subobject in any manner that it so chooses.

University of Gondar, Department of Computer Scienc Page 5


OOP: Chapter 3- Object Oriented Principles

Note:
 You must use the keyword super to call the superclass constructor, and the call must be
the first statement in the constructor. Invoking a superclass constructor's name in a subclass
causes a syntax error.
 A constructor is used to construct an instance of a class. Unlike properties and methods,
the constructors of a superclass are not inherited in the subclass. They can only be invoked
from the constructors of the subclasses, using the keyword super.
Constructor Chaining
A constructor may invoke an overloaded constructor or its superclass's constructor. If neither of
them is invoked explicitly, the compiler puts super() as the first statement in the constructor. For
example, In any case, constructing an instance of a class invokes the constructors of all the
superclasses along the inheritance chain. A superclass's constructor is called before the subclass's
constructor. This is called constructor chaining. Consider the following code:

class Parent
{
public Parent()
{
System.out.println("Parent class no-args constructor called");
}
public Parent(String name)
{
System.out.println("Parent class Parameterized constructor called by "+name);
}
}
public class Child extends Parent Program Output
{
public Child()
{ Parent class Parameterized constructor called by JVM
this("JVM"); Child class Parameterized constructor called by JVM
System.out.println("Child class no-args constructor called"); Child class no-args constructor called
}
public Child(String name)
{
super("JVM");
System.out.println("Child class Parameterized constructor called by "+name);
}
public static void main(String args[])
{
Child c = new Child();
}
}
b. Access Superclass Members

There is a second form of super that acts somewhat like this, except that it always refers to the
superclass of the subclass in which it is used. This usage has the following general form:
super.member
Here, member can be either a method or an instance variable.

This form of super is most applicable to situations in which member names of a subclass hide
members by the same name in the superclass. Consider this simple class hierarchy:

University of Gondar, Department of Computer Scienc Page 6


OOP: Chapter 3- Object Oriented Principles

// Using super to overcome name hiding.


class A {
int i;
}
// Create a subclass by extending class A.
class B extends A {
int i; // this i hides the i in A
B(int a, int b) {
super.i = a; // i in A
i = b; // i in B
}
void show() {
System.out.println("i in superclass: " + super.i);
System.out.println("i in subclass: " + i); Program Output
}
}
class UseSuper { i in superclass: 1
public static void main(String args[]) { i in subclass: 2
B subOb = new B(1, 2);
subOb.show();
}
}

Although the instance variable i in B hides the i in A, super allows access to the i defined in the
superclass. super can also be used to call methods that are hidden by a subclass. The syntax is
like this: super.method(parameters);

3.5. Preventing Inheritance: Final Classes and Methods


Occasionally, you want to prevent someone from forming a subclass from one of your classes.
Classes that cannot be extended are called final classes, and you use the final modifier in the
definition of the class to indicate this. For example, let us suppose we want to prevent others from
subclassing the Triangle class. Then, we simply declare the class by using the final modifier as
follows:

final class Triangle extends TwoDShape


{
...
}
Here is another example of a final class:
final class A {
// ...
}
// The following class is illegal.
class B extends A { // ERROR! Can't subclass A
// ...
}
As the comments imply, it is illegal for B to inherit A since A is declared as final.
You can also make a specific method in a class final. If you do this, then no subclass can override
that method. (All methods in a final class are automatically final.) For example:
class A {
final void meth() {
System.out.println("This is a final method.");

University of Gondar, Department of Computer Scienc Page 7


OOP: Chapter 3- Object Oriented Principles

}
}
class B extends A {
void meth() { // ERROR! Can't override.
System.out.println("Illegal!");
}}
Because meth( ) is declared as final, it cannot be overridden in B. If you attempt to do so, a
compile-time error will result.
In addition to the uses of final just shown, final can also be applied to variables to create named
constants. If you precede a class variable’s name with final, its value cannot be changed throughout
the lifetime of your program. For example, final double PI=3.14;
3.6.Abstract Classes
Sometimes you will want to create a superclass that defines only a generalized form that will be
shared by all of its subclasses, leaving it to each subclass to fill in the details. Such a class
determines the nature of the methods that the subclasses must implement but does not, itself,
provide an implementation of one or more of these methods. One way this situation can occur is
when a superclass is unable to create a meaningful implementation for a method.

As you move up the inheritance hierarchy, classes become more general and probably more
abstract. At some point, the ancestor class becomes so general that you think of it more as a basis
for other classes than as a class with specific instances you want to use. Consider, for example, the
following class hierarchy. An employee is a person, and so is a student
Person

Employee Student

Figure 3.1 Inheritance diagram for Person and its subclasses


Why bother with so high a level of abstraction? There are some attributes that make sense for
every person, such as the name. Both students and employees have names, and introducing a
common superclass lets us factor out the getName method to a higher level in the inheritance
hierarchy.

Abstract class is declared by preceding its class declaration with the abstract specifier. Since an
abstract class does not define a complete implementation, there can be no objects of an abstract
class. Thus, attempting to create an object of an abstract class by using new will result in a compile-
time error.
A class that is declared using “abstract” keyword is known as abstract class. It can have abstract
methods (methods without body) as well as concrete methods (regular methods with body). A
normal class (non-abstract class) cannot have abstract methods.

Let s consider the class TwoDShape used in the preceding example. The definition of area( ) is simply a
placeholder. It will not compute and display the area of any type of object. Since the TwoDShape area
differs from one TwoDShape to another, there is no point to implement this method in parent class. This is
because every child class must override this method to give its own implementation details.

University of Gondar, Department of Computer Scienc Page 8


OOP: Chapter 3- Object Oriented Principles

Consider the class Triangle. It has no meaning if area( ) is not defined. In this case, you want
some way to ensure that a subclass does, indeed, override all necessary methods. Java’s solution
to this problem is the abstract method.
An abstract method is created by specifying the abstract type modifier. An abstract method
contains no body and is, therefore, not implemented by the superclass. Thus, a subclass must
override it--it cannot simply use the version defined in the superclass. To declare an abstract
method, use this general form:
abstract type name(parameter-list);
As you can see, no method body is present. The abstract modifier can be used only on normal
methods. It cannot be applied to static methods or to constructors.
A class that contains one or more abstract methods must also be declared as abstract. When a
subclass inherits an abstract class, it must implement all of the abstract methods in the superclass.
If it doesn’t, then the subclass must also be specified as abstract. Thus, the abstract attribute is
inherited until such time as a complete implementation is achieved.

Using an abstract class, you can improve the TwoDShape class. Since there is no meaningful
concept of area for an undefined two-dimensional figure, the following version of the preceding
program declares area( ) as abstract inside TwoDShape, and TwoDShape as abstract. This, of
course, means that all classes derived from TwoDShape must override area( ).

Example:
package oopconcepts;
// Create an abstract class.
public abstract class TwoDShape { width + " and " + height);
private double width; }
private double height; // Now, area() is abstract.
private String name; abstract double area();
// A default constructor. }
TwoDShape() { // A subclass of TwoDShape for triangles.
width = height = 0.0; class Triangle extends TwoDShape {
name = "null"; private String style;
} // A default constructor.
// Parameterized constructor. Triangle() {
TwoDShape(double w, double h, String n) super();
{ width = w; style = "null";
height = h; }
name = n; // Constructor for Triangle.
} Triangle(String s, double w, double h) {
// Construct object with equal width and height. super(w, h, "triangle");
TwoDShape(double x, String n) { style = s;
width = height = x; }
name = n; // Construct an isosceles triangle.
} Triangle(double x) {
// Accessor methods for width and height. super(x, "triangle"); // call superclass
double getWidth() { return width; } constructor
double getHeight() { return height; } style = "isosceles";
void setWidth(double w) { width = w; } }
void setHeight(double h) { height = h; } double area() {
String getName() { return name; } return getWidth() * getHeight() / 2;
void showDim() { }
System.out.println("Width and height are " void showStyle() {
+ System.out.println("Triangle is " + style);

University of Gondar, Department of Computer Scienc Page 9


OOP: Chapter 3- Object Oriented Principles

}} Rectangle(double x) {
// A subclass of TwoDShape for rectangles. super(x, "rectangle"); // call superclass
class Rectangle extends TwoDShape { constructor
// A default constructor. }
Rectangle() { boolean isSquare() {
super(); } if(getWidth() == getHeight()) return true;
// Constructor for Rectangle. return false;
Rectangle(double w, double h) { }
super(w, h, "rectangle"); // call superclass double area() {
constructor return getWidth() * getHeight();
} }
// Construct a square. }

package oopconcepts;
public class AbstractShape {
Program Output
public static void main(String[] args) {
TwoDShape shapes[] = new TwoDShape[4]; object is triangle
shapes[0] = new Triangle("right", 8.0, 12.0); Width and height are 8.0 and 12.0
Area is 48.0
shapes[1] = new Rectangle(10); Triangle is right
shapes[2] = new Rectangle(10, 4);
shapes[3] = new Triangle(7.0); object is rectangle
for(int i=0; i < shapes.length; i++) { Width and height are 10.0 and 10.0
System.out.println("object is " + shapes[i].getName()); Area is 100.0
shapes[i].showDim(); Rectangle is square true
System.out.println("Area is " + shapes[i].area());
if(shapes[i].getName()=="triangle") object is rectangle
((Triangle) shapes[i]).showStyle(); Width and height are 10.0 and 4.0
if(shapes[i].getName()=="rectangle") Area is 40.0
System.out.println("Rectangle is square " + Rectangle is square false
((Rectangle) shapes[i]).isSquare());
object is triangle
System.out.println(); Width and height are 7.0 and 7.0
}}} Area is 24.5
As the program illustrates, all subclasses of TwoDShape must Triangle is isosceles
override area( ). Of course, it is still possible to create an object
reference of type TwoDShape, which the program does.
However, it is no longer possible to declare objects of type TwoDShape. Because of this, in main(
) the shapes array has been shortened to 4, and a generic TwoDShape object is no longer created.
One last point: notice that TwoDShape still includes the showDim( ) and getName( ) methods
and that these are not modified by abstract. It is perfectly acceptable--indeed, quite common--for
an abstract class to contain concrete methods which a subclass is free to use as is. Only those
methods declared as abstract need be overridden by subclasses.

3.7.Interface
In object-oriented programming, it is sometimes helpful to define what a class must do but not
how it will do it. You have already seen an example of this: the abstract method. An abstract
method defines the signature for a method but provides no implementation. A subclass must
provide its own implementation of each abstract method defined by its superclass. Thus, an
abstract method specifies the interface to the method but not the implementation. While abstract
classes and methods are useful, it is possible to take this concept a step further. In Java, you can
fully separate a class’s interface from its implementation by using the keyword interface.

University of Gondar, Department of Computer Scienc Page 10


OOP: Chapter 3- Object Oriented Principles

An interface is a class like construct that contains only constants and abstract methods. In many
ways, an interface is similar to an abstract class, but an abstract class can contain variables and
concrete methods as well as constants and abstract methods.
3.7.1. Declaring Interfaces
The interface keyword is used to declare an interface. Here is the general form of an interface :
access interface name {
ret-type method-name1(param-list);
ret-type method-name2(param-list);
type var1 = value;
type var2 = value;
// ...
ret-type method-nameN(param-list);
type varN = value;
}
Here, access is either public or not used. When no access specifier is included, then default access
results, and the interface is available only to other members of its package. When it is declared as
public, the interface can be used by any other code. (When an interface is declared public, it must
be in a file of the same name.) name is the name of the interface and can be any valid identifier.
Methods are declared using only their return type and signature. They are, essentially, abstract
methods. As explained, in an interface, no method can have an implementation.

Thus, each class that includes an interface must implement all of the methods. In an interface,
methods are implicitly public. Variables declared in an interface are not instance variables.
Instead, they are implicitly public, final, and static and must be initialized. Thus, they are
essentially constants.

Here is an example of an interface definition. It specifies the interface to a class that generates a
series of numbers.
public interface Series {
int getNext(); // return next number in series
void reset(); // restart
void setStart(int x); // set starting value
}
This interface is declared public so that it can be implemented by code in any package.
3.7.2. Implementing Interfaces
Once an interface has been defined, one or more classes can implement that interface. To
implement an interface, include the implements clause in a class definition and then create the
methods defined by the interface. The general form of a class that includes the implements clause
looks like this:
access class classname implements interface {
// class-body
}
Here, access is either public or not used. To implement more than one interface, the interfaces are
separated with a comma. The methods that implement an interface must be declared public. Also,
the type signature of the implementing method must match exactly the type signature specified in
the interface definition.

University of Gondar, Department of Computer Scienc Page 11


OOP: Chapter 3- Object Oriented Principles

Here is an example that implements the Series interface shown earlier. It creates a class called
ByTwos, which generates a series of numbers, each two greater than the previous one.
// Implement Series.
class ByTwos implements Series {
int start;
int val;
ByTwos() {
start = 0;
val = 0;
}
public int getNext() {
val += 2;
return val;
}
public void reset() {
start = 0;
val = 0;
}
public void setStart(int x) {
start = x;
val = x;
}
}
Notice that the methods getNext( ), reset( ), and setStart( ) are declared using the public access
specifier. This is necessary. Whenever you implement a method defined by an interface, it must
be implemented as public because all members of an interface are implicitly public. Here is a
class that demonstrates ByTwos.
public class InterfaceDemo { Program Output
public static void main(String args[]) {
ByTwos ob = new ByTwos(); Next value is 2
for(int i=0; i < 5; i++) Next value is 4
System.out.println("Next value is " +ob.getNext()); Next value is 6
System.out.println("\nResetting"); Next value is 8
Next value is 10
ob.reset();
Resetting
for(int i=0; i < 5; i++) Next value is 2
System.out.println("Next value is " + ob.getNext()); Next value is 4
System.out.println("\nStarting at 100"); Next value is 6
ob.setStart(100); Next value is 8
for(int i=0; i < 5; i++) Next value is 10
System.out.println("Next value is " + ob.getNext()); Starting at 100
} Next value is 102
Next value is 104
}
Next value is 106
It is both permissible and common for classes that implement interfaces Next value is 108
to define additional members of their own. For example, the following Next value is 110
version of ByTwos adds the method getPrevious( ), which returns the
previous value.
// Implement Series and add getPrevious().
class ByTwos implements Series {
int start;
int val;
int prev;
ByTwos() {
start = 0;
val = 0;

University of Gondar, Department of Computer Scienc Page 12


OOP: Chapter 3- Object Oriented Principles

prev = -2;
}
public int getNext() {
prev = val;
val += 2;
return val;
}
public void reset() {
start = 0;
val = 0;
prev = -2;
}
public void setStart(int x) {
start = x;
val = x;
prev = x - 2;
}
int getPrevious() {
return prev;
}
}
Notice that the addition of getPrevious( ) required a change to the implementations of the methods
defined by Series. However, since the interface to those methods stays the same, the change is
seamless and does not break preexisting code. This is one of the advantages of interfaces.
As explained, any number of classes can implement an interface. For example, here is a class
called ByThrees that generates a series that consists of multiples of three.
// Implement Series.
class ByThrees implements Series {
int start;
int val;
ByThrees() {
start = 0;
val = 0;
}
public int getNext() {
val += 3;
return val;
}
public void reset() {
start = 0;
val = 0;
}
public void setStart(int x) {
start = x;
val = x;
}}
Notice: If a class includes an interface but does not fully implement the methods defined by that
interface, then that class must be declared as abstract. No objects of such a class can be created,
but it can be used as an abstract superclass, allowing subclasses to provide the complete
implementation.

University of Gondar, Department of Computer Scienc Page 13


OOP: Chapter 3- Object Oriented Principles

3.7.3. Interfaces and Inheritance


It is possible for a Java interface to inherit from another Java interface, just like classes can
inherit from other classes. You specify inheritance using the extends keyword. Here is a simple
interface inheritance example:
public interface MySuperInterface {
public void sayHello();
}
public interface MySubInterface extends MySuperInterface {
public void sayGoodbye();
}
The interface MySubInterface extends the interface MySuperInterface. That means, that
the MySubInterface inherits all field and methods from MySuperInterface. That then means, that
if a class implements MySubInterface, that class has to implement all methods defined in
both MySubInterface and MySuperInterface.
Unlike classes, interfaces can actually inherit from multiple superinterfaces. You specify that by
listing the names of all interfaces to inherit from, separated by comma. A class implementing an
interface which inherits from multiple interfaces must implement all methods from the interface
and its superinterfaces.
Here is an example of a Java interface that inherits from multiple interfaces:
interface Printable{
void print();
}
interface Showable{
void show();
}
public class InterfaceTest implements Printable,Showable{ Program Output
public void print(){System.out.println("Hello");}
public void show(){System.out.println("Welcome");}
Hello
public static void main(String args[]){
InterfaceTest obj = new InterfaceTest (); Welcome
obj.print();
obj.show();
} }
3.7.4. Classes and Interfaces
An interface is similar to a class in the following ways −
 An interface can contain any number of methods.
 An interface is written in a file with a .java extension, with the name of the interface matching the
name of the file.
 The byte code of an interface appears in a .class file.
 Interfaces appear in packages, and their corresponding bytecode file must be in a directory structure
that matches the package name.
However, an interface is different from a class in several ways, including −
 You cannot instantiate an interface.
 An interface does not contain any constructors.
 All of the methods in an interface are abstract.
 An interface cannot contain instance fields. The only fields that can appear in an interface must be
declared both static and final.
 An interface is not extended by a class; it is implemented by a class.
 An interface can extend multiple interfaces.

University of Gondar, Department of Computer Scienc Page 14


OOP: Chapter 3- Object Oriented Principles

Interfaces vs. Abstract Classes


An interface can be used the same way as an abstract class, but declaring an interface is different
from declaring an abstract class. The following table summarizes the differences.

Variables Constructors Methods

Abstract class No restrictions Constructors are invoked by No restrictions


subclasses through
constructor chaining. An
abstract class cannot be
instantiated using the new
operator.

Interface All variables No constructors. An interface All methods


must be cannot be instantiated using must be public
public the new operator. abstract instance
static final methods

Table 3.1 Interfaces vs. Abstract Classes


4. Polymorphism
Polymorphism (from the Greek, meaning “many forms”) is the ability of an object to take on many
forms. Modeling polymorphism in a programming language lets you to create a uniform interface
to different kinds of operands, arguments, and objects. The result is code that is more concise and
easier to maintain. There are two types of polymorphism in java: compile time polymorphism and
runtime polymorphism.
4.1. Compile time polymorphism
Compile time polymorphism is called early binding (static polymorphism).In compile
polymorphism the compiler decides how some messages are to be carried out (which methods to
call). Compile time polymorphism is achieved by using operator overloading and method
overloading.
int m(2), n(3);
float x(4.5), y(6.7);
Rational r(8,9), s(10,11);
m = 2 + n; // Integer addition
x = 3.1 + y; // Floating point addition
Rational t = r + s; // Rational addition
System.out.println(m +x + t); // Different output results depend on type
The compiler generates the function definition and decides which function to call based on the
argument lists.
Method Overloading
In Java, two or more methods within the same class can share the same name, as long as their
parameter declarations are different. When this is the case, the methods are said to be
overloaded, and the process is referred to as method overloading. Method overloading is one of
the ways that Java implements polymorphism.
In general, to overload a method, simply declare different versions of it. The compiler takes care
of the rest. You must observe one important restriction: the type and/or number of the parameters
of each overloaded method must differ. It is not sufficient for two methods to differ only in their

University of Gondar, Department of Computer Scienc Page 15


OOP: Chapter 3- Object Oriented Principles

return types. (Return types do not provide sufficient information in all cases for Java to decide
which method to use.) Of course, overloaded methods may differ in their return types, too. When
an overloaded method is called, the version of the method whose parameters match the arguments
is executed.
Here is a simple example that illustrates method overloading:
// Demonstrate method overloading.
class Overload {
void ovlDemo() {
System.out.println("No parameters");
}
// Overload ovlDemo for one integer parameter.
void ovlDemo(int a) {
System.out.println("One parameter: " + a);
}
// Overload ovlDemo for two integer parameters.
int ovlDemo(int a, int b) {
System.out.println("Two parameters: " + a + " " + b);
return a + b;
}
// Overload ovlDemo for two double parameters.
double ovlDemo(double a, double b) {
System.out.println("Two double parameters: " + a + " "+ b);
return a + b;
}
} Program Output
public class OverloadDemo {
public static void main(String args[]) {
Overload ob = new Overload(); No parameters
int resI; One parameter: 2
double resD;
Two parameters: 4 6
// call all versions of ovlDemo()
ob.ovlDemo();
Result of ob.ovlDemo(4, 6): 10
System.out.println(); Two double parameters: 1.1 2.32
ob.ovlDemo(2); Result of ob.ovlDemo(1.1, 2.32): 3.42
System.out.println();
resI = ob.ovlDemo(4, 6);
System.out.println("Result of ob.ovlDemo(4, 6): " +resI);
System.out.println();
resD = ob.ovlDemo(1.1, 2.32);
System.out.println("Result of ob.ovlDemo(1.1, 2.32): " +resD);
}
}
As you can see, ovlDemo( ) is overloaded four times. The first version takes no parameters, the
second takes one integer parameter, the third takes two integer parameters, and the fourth takes
two double parameters. Notice that the first two versions of ovlDemo( ) return void, and the
second two return a value. This is perfectly valid, but as explained, overloading is not affected
one way or the other by the return type of a method. Thus, attempting to use these two versions
of ovlDemo( ) will cause an error.
// One ovlDemo(int) is OK.
void ovlDemo(int a) {
System.out.println("One parameter: " + a);
}
/* Error! Two ovlDemo(int)s are not OK even though
return types differ.

University of Gondar, Department of Computer Scienc Page 16


OOP: Chapter 3- Object Oriented Principles

*/
int ovlDemo(int a) {
System.out.println("One parameter: " + a);
return a * a;}
As the comments suggest, the difference in their return types is insufficient for the purposes of
overloading.
Overloading Constructors
Like methods, constructors can also be overloaded. Doing so allows you to construct objects in a
variety of ways. For example, consider the following program:
// Demonstrate an overloaded constructor.
class MyClass {
int x;
MyClass() { Program Output
System.out.println("Inside MyClass().");
x = 0;
} Inside MyClass().
MyClass(int i) { Inside MyClass(int).
System.out.println("Inside MyClass(int).");
Inside MyClass(double).
x = i;
}
Inside MyClass(int, int).
MyClass(double d) { t1.x: 0
System.out.println("Inside MyClass(double)."); t2.x: 88
x = (int) d; t3.x: 17
} t4.x: 8
MyClass(int i, int j) {
System.out.println("Inside MyClass(int, int).");

x = i * j;
}
}
public class OverloadConsDemo {
public static void main(String args[]) {
MyClass t1 = new MyClass();
MyClass t2 = new MyClass(88);
MyClass t3 = new MyClass(17.23);
MyClass t4 = new MyClass(2, 4);
System.out.println("t1.x: " + t1.x);
System.out.println("t2.x: " + t2.x);
System.out.println("t3.x: " + t3.x);
System.out.println("t4.x: " + t4.x);
}
}
MyClass( ) is overloaded four ways, each constructing an object differently. The proper
constructor is called based upon the parameters specified when new is executed. By overloading
a class’ constructor, you give the user of your class flexibility in the way objects are constructed.
One of the most common reasons that constructors are overloaded is to allow one object to
initialize another. For example, consider this program that uses the Summation class to compute
the summation of an integer value.
// Initialize one object with another.
class Summation {
int sum;
// Construct from an int.
Summation(int num) {
sum = 0;

University of Gondar, Department of Computer Scienc Page 17


OOP: Chapter 3- Object Oriented Principles

for(int i=1; i <= num; i++)


sum += i;
}
// Construct from another object.
Summation(Summation ob) {
sum = ob.sum;
}
} Program Output
class SumDemo {
public static void main(String args[]) {
Summation s1 = new Summation(5);
Summation s2 = new Summation(s1);
s1.sum: 15
System.out.println("s1.sum: " + s1.sum); s2.sum: 15
System.out.println("s2.sum: " + s2.sum);
}
}
Often, as this example shows, an advantage of providing a constructor that uses one object to
initialize another is efficiency. In this case, when s2 is constructed, it is not necessary to recompute
the summation. Of course, even in cases when efficiency is not an issue, it is often useful to provide
a constructor that makes a copy of an object.
4.2.Run time polymorphism
Runtime polymorphism also called ate binding (dynamic polymorphism). Runtime
polymorphism means the decision about which method to invoke is made at runtime and not at
compile time. Runtime polymorphism allows a member methods call to be resolved at run time,
according to the run-time type of an object reference. This permits each user-defined class in an
inheritance hierarchy to have a different implementation of a particular method. Application
programs can then apply that method to an object without needing to know the specifics of the
class that the object belongs to. Run time polymorphism can be achieved through method
overriding.
Method Overriding
In a class hierarchy, when a method in a subclass has the same return type and signature as a
method in its superclass, then the method in the subclass is said to override the method in the
superclass. When an overridden method is called from within a subclass, it will always refer to the
version of that method defined by the subclass. The version of the method defined by the superclass
will be hidden. Consider the following:
// Method overriding.
class A {
int i, j;
A(int a, int b) {
i = a;
j = b; Program Output
}
// display i and j
void show() {
System.out.println("i and j: " + i + " " + j); k: 3
}
}
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;

University of Gondar, Department of Computer Scienc Page 18


OOP: Chapter 3- Object Oriented Principles

}
// display k – this overrides show() in A
void show() {
System.out.println("k: " + k);
}}
public class Override {
public static void main(String args[]) {
B subOb = new B(1, 2, 3);
subOb.show(); // this calls show() in B
}
}
Overridden Methods Support Polymorphism
While the above example demonstrates the mechanics of method overriding, it doesn’t show its
power. Method overriding forms the basis for one of Java’s most powerful concepts: dynamic
method dispatch. Dynamic method dispatch is the mechanism by which a call to an overridden
method is resolved at run time rather than compile time. Dynamic method dispatch is important
because this is how Java implements run-time polymorphism.
Let’s begin by restating an important principle: a superclass reference variable can refer to a
subclass object. Java uses this fact to resolve calls to overridden methods at run time. Here’s how.
When an overridden method is called through a superclass reference, Java determines which
version of that method to execute based upon the type of the object being referred to at the time
the call occurs. Thus, this determination is made at run time. When different types of objects are
referred to, different versions of an overridden method will be called. In other words, it is the type
of the object being referred to (not the type of the reference variable) that determines which version
of an overridden method will be executed. Therefore, if a superclass contains a method that is
overridden by a subclass, then when different types of objects are referred to through a superclass
reference variable, different versions of the method are executed.
Here is an example that illustrates dynamic method dispatch:
// Demonstrate dynamic method dispatch.
class Sup {
void who() {
System.out.println("who() in Sup");
}}
class Sub1 extends Sup { Program Output
void who() {
System.out.println("who() in Sub1");
}}
class Sub2 extends Sup { who() in Sup
void who() { who() in Sub1
System.out.println("who() in Sub2"); who() in Sub2
}}
public class DynDispDemo {
public static void main(String args[]) {
Sup superOb = new Sup();
Sub1 subOb1 = new Sub1();
Sub2 subOb2 = new Sub2();
Sup supRef;
supRef = superOb;
supRef.who();
supRef = subOb1;
supRef.who();
supRef = subOb2;

University of Gondar, Department of Computer Scienc Page 19


OOP: Chapter 3- Object Oriented Principles

supRef.who();
}}
This program creates a superclass called Sup and two subclasses of it, called Sub1 and Sub2. Sup
declares a method called who( ), and the subclasses override it. Inside the main( ) method, objects
of type Sup, Sub1, and Sub2 are declared. Also, a reference of type Sup, called supRef, is
declared. The program then assigns a reference to each type of object to supRef and uses that
reference to call who( ). As the output shows, the version of who( ) executed is determined by the
type of object being referred to at the time of the call, not by the class type of supRef.

Rules of method overriding in Java


 Argument list: The argument list at the time of overriding method need to be same as that
of the method of parent class. The data types of the arguments along with their sequence
must have to be preserved as it is in the overriding method.
 Access Modifier: The Access Modifier present in the overriding method (method of
subclass) cannot be more restrictive than that of overridden method of parent class.
 The private, static and final methods can’t be overridden as they are local to the class.
Upcasting and Downcasting
When reference variable of Parent class refers to the object of Child class, it is known as upcasting.
For example:

Upcasting is a form of casting where you cast up the inheritance hierarchy from a subtype to a
supertype. No cast operator is involved because the subtype is a specialization of the supertype.
For example, TwoDShape s = new Triangle(); upcasts from Triangle to TwoDShape. This makes
sense because a triangle is a kind of two dimensional shape.

After upcasting Triangle to TwoDShape, you cannot call triangle-specific methods, such as
a showStyle() method that returns the traingl’s style, because Triangle-specific methods are not
part of TwoDShape's interface.

It is always possible to cast an instance of a subclass to a variable of a superclass (known as


upcasting), because an instance of a subclass is always an instance of its superclass. When casting
an instance of a superclass to a variable of its subclass (known as downcasting), explicit casting
must be used to confirm your intention to the compiler with the (SubclassName) cast notation.
For the casting to be successful, you must make sure that the object to be cast is an instance of the
subclass. If the superclass object is not an instance of the subclass, a runtime ClassCastException
occurs. For example,
(Triangle) shapes.showStyle();
Downcasting requires explicit type casting operator in the form of prefix operator. A subclass
object can be substituted for its superclass, but the reverse is not always true.

University of Gondar, Department of Computer Scienc Page 20

You might also like