Module 3
Module 3
MODULE 3
Class is a basis of OOP languages. It is a logical construct which defines shape and nature of an object.
Entire Java is built upon classes.
3.1 Inheritance
Inheritance is one of the building blocks of object oriented programming languages. It allows creation of
classes with hierarchical relationship among them. Using inheritance, one can create a general class that
defines traits common to a set of related items. This class can then be inherited by other, more specific
classes, each adding those things that are unique to it. In the terminology of Java, a class that is inherited
is called a superclass. The class that does the inheriting is called a subclass. Therefore, a subclass is a
specialized version of a superclass. It inherits all of the instance variables and methods defined by the
superclass and add its own, unique elements. Through inheritance, one can achieve re-usability of the
code.
In Java, inheritance is achieved using the keyword extends. The syntax is given below
class A
{
int i, j;
void showij()
{
System.out.println("i and j: " + i + " " + j);
}
}
class B extends A
{
int k;
void showk()
{
System.out.println("k: " + k);
}
void sum()
{
System.out.println("i+j+k: " + (i+j+k));
}
}
class SimpleInheritance
{
public static void main(String args[])
{
A superOb = new A();
B subOb = new B();
superOb.i = 10;
superOb.j = 20;
System.out.println("Contents of superOb: ");
superOb.showij();
subOb.i = 7;
subOb.j = 8;
subOb.k = 9;
System.out.println("Contents of subOb: ");
subOb.showij();
subOb.showk();
Note that, private members of the super class can not be accessed by the sub class. The subclass
contains all non-private members of the super class and also it contains its own set of members to
achieve specialization.
superclass
subclass
Multilevel Inheritance: If several classes are inherited one after the other in a hierarchical
manner, it is known as multilevel inheritance, as shown below –
class Base
{
void dispB()
{
System.out.println("Super class " );
}
}
class Derived extends Base
{
void dispD()
{
System.out.println("Sub class ");
}
}
class Demo
{
public static void main(String args[])
{
Base b = new Base();
Derived d=new Derived();
Note that, the type of reference variable decides the members that can be accessed, but not the type
of the actual object. That is, when a reference to a subclass object is assigned to a superclass
reference variable, you will have access only to those parts of the object defined by the superclass.
class Box
{
double w, h, b;
Also, if the data members of super class are private, then we can’t even write such a code in subclass
constructor. If we use super() to call superclass constructor, then it must be the first statement
executed inside a subclass constructor as shown below –
class Box
{
double w, h, b;
Box(double wd, double ht, double br)
{
w=wd; h=ht; b=br;
}
}
class Demo
{
public static void main(String args[])
{
ColourBox b=new ColourBox(2,3,4, 5);
}
}
Here, we are creating the object b of the subclass ColourBox . So, the constructor of this class is
invoked. As the first statement within it is super(wd, ht, br), the constructor of superclass Box is
invoked, and then the rest of the statements in subclass constructor ColourBox are executed.
To access superclass member variable when there is a duplicate variable name in the
subclass: 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.
class A
{
int a;
}
class B extends A
{
int a; //duplicate variable a
B(int x, int y)
{
super.a=x; //accessing superclass a
a=y; //accessing own member a
}
void disp()
{
System.out.println("super class a: "+ super.a);
System.out.println("sub class a: "+ a);
}
}
class SuperDemo
{
public static void main(String args[])
{
B ob=new B(2,3);
ob.disp();
}
}
class A
{ int a;
}
class B extends A
{ int b;
}
class C extends B
{ int c;
class MultiLevel
{
public static void main(String args[])
{
C ob=new C(2,3,4);
ob.disp();
}
}
class A
{
A()
{
System.out.println("A's constructor.");
}
}
class B extends A
{
B()
{
System.out.println("B's constructor.");
}
}
class C extends B
{
C()
{
System.out.println("C's constructor.");
}
}
class CallingCons
{
public static void main(String args[])
{
C c = new C();
}
}
Output:
A's constructor
B's constructor
C's constructor
class A
{
int i, j;
A(int a, int b)
{
i = a;
j = b;
}
void show() //suppressed
{
System.out.println("i and j: " + i + " " + j);
}
}
class B extends A
{
int k;
B(int a, int b, int c)
{
super(a, b);
k = c;
}
void show() //Overridden method
{
System.out.println("k: " + k);
}
}
class Override
{
public static void main(String args[])
{
B subOb = new B(1, 2, 3);
subOb.show();
}
}
Output:
k: 3
Note that, above program, only subclass method show() got called and hence only k got displayed. That
is, the show() method of super class is suppressed. If we want superclass method also to be called, we
can re-write the show() method in subclass as –
void show()
{
super.show(); // this calls A's show()
System.out.println("k: " + k);
}
Method overriding occurs only when the names and the type signatures of the two methods (one in
superclass and the other in subclass) are identical. If two methods (one in superclass and the other in
subclass) have same name, but different signature, then the two methods are simply overloaded.
class A
{
void callme()
{
System.out.println("Inside A");
}
}
class B extends A
{
void callme()
{
System.out.println("Inside B");
}
}
class C extends A
{
void callme()
{
System.out.println("Inside C");
}
}
class Dispatch
{
public static void main(String args[])
{
A a = new A();
B b = new B();
C c = new C();
A r; //Superclass reference
r = a; //holding subclass object
r.callme();
r = b;
r.callme();
r = c;
r.callme();
}
}
A class containing at least one abstract method is called as abstract class. Abstract classes can not be
instantiated, that is one cannot create an object of abstract class. Whereas, a reference can be created
for an abstract class.
abstract class A
{
abstract void callme();
void callmetoo()
{
System.out.println("This is a concrete method.");
}
}
class B extends A
{
void callme() //overriding abstract method
{
System.out.println("B's implementation of callme.");
}
}
class AbstractDemo
{
public static void main(String args[])
{
B b = new B(); //subclass object
b.callme(); //calling abstract method
b.callmetoo(); //calling concrete method
}
}
Example: Write an abstract class shape, which has an abstract method area(). Derive three classes
Triangle, Rectangle and Circle from the shape class and to override area(). Implement run-time
polymorphism by creating array of references to supeclass. Compute area of different shapes and display
the same.
Solution:
class AbstractDemo
{
public static void main(String args[])
{
Shape r[]={new Triangle(3,4), new Rectangle(5,6),new Circle(2)};
for(int i=0;i<3;i++)
System.out.println(r[i].area());
}
}
Output:
Area of Triangle is:6.0
Area of Rectangle is:30.0
Area of Circle is:12.5664
Note that, here we have created array r, which is reference to Shape class. But, every element in r is
holding objects of different subclasses. That is, r[0] holds Triangle class object, r[1] holds Rectangle class
object and so on. With the help of array initialization, we are achieving this, and also, we are calling
respective constructors. Later, we use a for-loop to invoke the method area() defined in each of these
classes.
To create the equivalent of a named constant: A variable can be declared as final. Doing so prevents
its contents from being modified. This means that you must initialize a final variable when it is declared.
For example:
final int FILE_NEW = 1;
final int FILE_OPEN = 2;
final int FILE_SAVE = 3;
final int FILE_SAVEAS = 4;
final int FILE_QUIT = 5;
It is a common coding convention to choose all uppercase identifiers for final variables. Variables
declared as final do not occupy memory on a per-instance basis. Thus, a final variable is essentially a
constant.
To prevent Inheritance: As we have discussed earlier, the subclass is treated as a specialized class
and superclass is most generalized class. During multi-level inheritance, the bottom most class will be
with all the features of real-time and hence it should not be inherited further. In such situations, we can
prevent a particular class from inheriting further, using the keyword final. For example –
final class A
{
// ...
}
class B extends A // ERROR! Can't subclass A
{
// ...
}
Note:
Declaring a class as final implicitly declares all of its methods as final, too.
It is illegal to declare a class as both abstract and final since an abstract class is incomplete by
itself and relies upon its subclasses to provide complete implementations
Method Purpose
Object clone( ) Creates a new object that is the same as the object being cloned.
void notifyAll( ) Resumes execution of all threads waiting on the invoking object.
The methods getClass( ), notify( ), notifyAll( ), and wait( ) are declared as final. You may override
the others. The equals( ) method compares the contents of two objects. It returns true if the objects
are equivalent, and false otherwise. The precise definition of equality can vary, depending on the
type of objects being compared. The toString( ) method returns a string that contains a description of
the object on which it is called. Also, this method is automatically called when an object is output
using println( ). Many classes override this method.
Interfaces:
A named collection of method declarations.
A Java interface is a collection of constants and abstract methods
Since all methods in an interface are abstract, the abstract modifier is usually left off
Using interface, you can specify what a class must do, but not how it does.
Interface fields are public, static and final by default, and methods are public and abstract.
Advantages of interfaces:
• It is used to achieve abstraction.
• By interface, we can support the functionality of multiple inheritances.
Syntax:
access_specifier interface interface_name
{
return-type method-name1(parameter-list);
return-type method-name2(parameter-list);
type final-varname1 = value;
type final-varname2 = value;
//...
return-type method-nameN(parameter-list);
type final-varnameN = value;
}
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 required by the
interface. The general form of a class that includes the implements clause looks like this:
A default method lets you define a default implementation for an interface method. In other words, by use of
a default method, it is possible for an interface method to provide a body, rather than being abstract.
During its development, the default method was also referred to as an extension method, and you will likely
see both terms used.
A primary motivation for the default method was to provide a means by which interfaces could be
expanded without breaking existing code.
Recall that there must be implementations for all methods defined by an interface. In the past, if a new
method were added to a popular, widely used interface, then the addition of that method would break
existing code because no implementation would be found for that new method.
The default method solves this problem by supplying an implementation that will be used if no other
implementation is explicitly provided. Thus, the addition of a default method will not cause preexisting code
to break.
Another motivation for the default method was the desire to specify methods in an interface that are,
essentially, optional, depending on how the interface is used. For example, an interface might define a
group of methods that act on a sequence of elements.
One of these methods might be called remove( ), and its purpose is to remove an element from the
sequence.
However, if the interface is intended to support both modifiable and nonmodifiable sequences, then
remove( ) is essentially optional because it won’t be used by nonmodifiable sequences. In the past, a class
that implemented a nonmodifiable sequence would have had to define an empty implementation of
remove( ), even though it was not needed.
Today, a default implementation for remove( ) can be specified in the interface that does nothing (or throws
an exception). Providing this default prevents a class used for nonmodifiable sequences from having to
define its own, placeholder version of remove( ). Thus, by providing a default, the interface makes the
implementation of remove( ) by a class optional.
for an implementing class to override it. In other words, if an implementing class does not provide its own
implementation, the default is used.
Notice that this is similar to the way that a static method in a class is called. The following shows an
example of a static method in an interface by adding one to MyIF, shown in the previous section. The static
method is getDefaultNumber( ). It returns zero.
A private interface method can be called only by a default method or another private method defined by the
same interface. Because a private interface method is specified private, it cannot be used by code outside
the interface in which it is defined.
This restriction includes subinterfaces because a private interface method is not inherited by a
subinterface. The key benefit of a private interface method is that it lets two or more default methods use a
common piece of code, thus avoiding code duplication. For example, here is another version of the
IntStack interface that has two default methods called popNElements( ) and skipAndPopNElements( ).
The first returns an array that contains the top N elements on the stack. The second skips a specified
number of elements and then returns an array that contains the next N elements. Both use a private
method called getElements( ) to obtain an array of the specified number of elements from the stack.
Question Bank: