Module 2 Part1
Module 2 Part1
MODULE 3
Syllabus:
Introducing Classes: Class Fundamentals, Declaring Objects, Assigning Object Reference Variables, Introducing
Methods, Constructors, The this Keyword, Garbage Collection, The finalize( ) Method, A Stack Class.
A Closer Look at Methods and Classes: Overloading Methods, Using Objects as Parameters, A Closer Look at
Argument Passing, Returning Objects, Recursion, Introducing Access Control, Understanding static, Introducing
final, Arrays Revisited.
Inheritance: Inheritance, Using super, Creating a Multilevel Hierarchy, When Constructors Are Called, Method
Overriding, Dynamic Method Dispatch, Using Abstract Classes, Using final with Inheritance, The Object Class.
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.
class classname
{
type var1;
type var2;
…….
type method1(para_list)
{
//body of method1
}
type method2(para_list)
{
//body of method2
}
………..
}
Here, classname is any valid name given to the class. Variables declared within a class are called as instance
variables because every instance (or object) of a class contains its own copy of these variables. The code is
contained within methods. Methods and instance variables collectively called as members of the class.
A Simple Class
Here we will consider a simple example for creation of class, creating objects and using members of the class. One
can store the following program in a single file called BoxDemo.java. (Or, two classes can be saved in two
different files with the names Box.java and BoxDemo.java.)
class Box
{
double w, h, d;
}
class BoxDemo
{
public static void main(String args[])
{
Box b1=new Box();
Box b2=new Box();
double vol;
b1.w=2;
b1.h=4;
b1.d=3;
b2.w=5;
b2.h=6;
b2.d=2;
vol=b1.w*b1.h*b1.d; System.out.println("Volume
of Box1 is " + vol);
vol=b2.w*b2.h*b2.d; System.out.println("Volume
of Box2 is " + vol);
}
}
When you compile above program, two class files will be created viz. Box.class and BoxDemo.class. Since
main() method is contained in BoxDemo.class, you need to execute the same.
In the above example, we have created a class Box which contains 3 instance variables w, h, d.
Box b1=new Box();
The above statement creates a physical memory for one object of Box class. Every object is an instance of a class,
and so, b1 and b2 will have their own copies of instance variables w, h and d. The memory layout for one object
allocation can be shown as –
Box Class
main()
{ Box Instance
Box b1 = new Box( );
}
BoxDemo Class
JVM Heap
We can even declare an object and allocate memory using a single statement – Box
b1=new Box();
Without the usage of new, the object contains null. Once memory is allocated dynamically, the object b1 contains
the address of real object created on the heap. The memory map is as shown in the following diagram –
Statement Effect
b1 = new Box();
b1 w
h
d
Closer look at new
The general form for object creation is –
obj_name = new class_name();
Here, class_name() is actually a constructor call. A constructor is a special type of member function invoked
automatically when the object gets created. The constructor usually contains the code needed for object
initialization. If we do not provide any constructor, then Java supplies a default constructor.
Java treats primitive types like byte, short, int, long, char, float, double and boolean as ordinary variables but
not as an object of any class. This is to avoid extra overhead on the heap memory and also to increase the efficiency
of the program. Java also provides the class-version of these primitive types that can be used only if necessary. We
will study those types later in detail.
With the term dynamic memory allocation, we can understand that the keyword new allocates memory for the
object during runtime. So, depending on the user’s requirement memory will be utilized. This will avoid the
problems with static memory allocation (either shortage or wastage of memory during runtime). If there is no
enough memory in the heap when we use new for memory allocation, it will throw a run-time exception.
Now both b1 and b2 refer to same object on the heap. The memory representation for two objects can be shown as –
w
b1
h
d
b2
Thus, any change made for the instance variables of one object affects the other object also. Although b1 and b2
both refer to the same object, they are not linked in any other way. For example, a subsequent assignment to b1 will
simply unhook b1 from the original object without affecting the object or affecting b2. For example:
Here, b1 has been set to null, but b2 still points to the original object.
NOTE that when you assign one object reference variable to another object reference variable, you are not creating
a copy of the object, you are only making a copy of the reference.
ret_type method_name(para_list)
{
//body of the method
return value;
}
Here, ret_type specifies the data type of the variable returned by the method. It may be any primitive
type or any other derived type including name of the same class. If the method does
not return any value, the ret_type should be specified as void.
method_name is any valid name given to the method
para_list is the list of parameters (along with their respective types) taken the method. It may be even
empty also.
body of method is a code segment written to carryout some process for which the method is meant for.
return is a keyword used to send value to the calling method. This line will be absent if the
ret_type is void.
Though it is possible to have classes with only instance variables as we did for Box class of Program 2.1, it is
advisable to have methods to operate on those data. Because, methods acts as interface to the classes. This allows
the class implementer to hide the specific layout of internal data structures behind cleaner method abstractions. In
addition to defining methods that provide access to data, you can also define methods that are used internally by the
class itself. Consider the following example –
class Box
{
double w, h, d;
void volume()
{
System.out.println("The volume is " + w*h*d);
}
}
class BoxDemo
{
public static void main(String args[])
{
Box b1=new Box();
Box b2=new Box();
b1.w=2;
b1.h=4;
b1.d=3;
b2.w=5;
b2.h=6;
b2.d=2;
b1.volume();
b2.volume();
}
}
In the above program, the Box objects b1 and b2 are invoking the member method volume() of the Box class to
display the volume. To attach an object name and a method name, we use dot (.) operator. Once the program control
enters the method volume(), we need not refer to object name to use the instance variables w, h and d.
Returning a value
In the previous example, we have seen a method which does not return anything. Now we will modify the above
program so as to return the value of volume to main() method.
class Box
{
double w, h, d;
double volume()
{
return w*h*d;
}
}
class BoxDemo
{
public static void main(String args[])
{
Box b1=new Box();
Box b2=new Box();
double vol;
b1.w=2;
b1.h=4;
b1.d=3;
b2.w=5;
b2.h=6;
b2.d=2;
As one can observe from above example, we need to use a variable at the left-hand side of the assignment operator
to receive the value returned by a method. On the other hand, we can directly make a method call within print
statement as shown in the last line of above program.
class Box
{
double w, h, d;
double volume()
{
return w*h*d;
}
class BoxDemo
{
public static void main(String args[])
{
Box b1=new Box();
Box b2=new Box();
b1.set(2,4,3);
b2.set(5,6,2);
In the above program, the Box class contains a method set() which take 3 parameters. Note that, the variables wd,
ht and dp are termed as formal parameters or just parameters for a method. The values passed like 2, 4, 3 etc.
are called as actual arguments or just arguments passed to the method.
3.5 Constructors
Constructor is a special type of member method which is invoked automatically when the object gets created.
Constructors are used for object initialization. They have same name as that of the class. Since they are called
automatically, there is no return type for them. Constructors may or may not take parameters.
class Box
{
double w, h, d;
double volume()
{
return w*h*d;
}
class BoxDemo
{
public static void main(String args[])
{
Box b1=new Box();
Box b2=new Box();
Box b3=new Box(2,4,3);
When we create two objects b1 and b2, the constructor with no arguments will be called and the all the instance
variables w, h and d are set to 5. Hence volume of b1 and b2 will be same (that is 125 in this example). But, when
we create the object b3, the parameterized constructor will be called and hence volume will be 24.
In the statement
classname ob= new classname();
the term classname() is actually a constructor call.
If the programmer does not provide any constructor of his own, then the above statement will call default
constructor.
If the programmer defines any constructor, then default constructor of Java can not be used.
So, if the programmer defines any parameterized constructor and later would like to create an object
without explicit initialization, he has to provide the default constructor by his own.
For example, the above program, if we remove ordinary constructor, the statements like Box
b1=new Box();
will generate error. To avoid the error, we should write a default constructor like – Box(){ }
Now, all the data members will be set to their respective default values.
Concept of Stack: A stack is a Last in First Out (LIFO) data structure. Following figure depicts the basic
operations on stack:
Inserting an element into a stack is known as push operation, whereas deleting an element from the stack is pop
operation. An attempt made to push an element into a full stack is stack overflow and an attempt to delete from
empty stack is stack underflow.
class Stack
{
int st[] = new int[5];
int top;
Stack()
{
top = -1;
}
int pop()
{
if(top==-1)
{
System.out.println("Stack underflow.");
return 0;
}
else
return st[top--];
}
}
class StackDemo
{
public static void main(String args[])
{
Stack mystack1 = new Stack();
Stack mystack2 = new Stack();
System.out.println("Contents of mystack1:");
for(int i=0; i<5; i++)
System.out.println(mystack1.pop());
System.out.println("Contents of mystack2:");
for(int i=0; i<5; i++)
System.out.println(mystack2.pop());
}
}
NOTE that, only the return type of the method is not sufficient for overloading.
class Overload
{
void test() //method without any arguments
{
System.out.println("No parameters");
}
class OverloadDemo
{
public static void main(String args[])
{
Overload ob = new Overload();
ob.test();
ob.test(10);
ob.test(10, 20);
ob.test(123.25);
}
}
class OverloadConstruct
{
int a, b;
OverloadConstruct()
{
System.out.println("Constructor without arguments");
}
OverloadConstruct(int x)
{
a=x;
System.out.println("Constructor with one argument:"+a);
}
OverloadConstruct(int x, int y)
{
a=x;
b=y;
System.out.println("Constructor with two arguments:"+ a +"\t"+ b);
}
}
class OverloadConstructDemo
{
public static void main(String args[])
{
OverloadConstruct ob1= new OverloadConstruct();
OverloadConstruct ob2= new OverloadConstruct(10);
OverloadConstruct ob3= new OverloadConstruct(5,12);
}
}
Output:
Constructor without arguments
Constructor with one argument:
10
Constructor with two arguments: 5 12
class Test
{
int a, b;
Test(int i, int
j)
{
Dept of ISE, SCE
14
Basics of Java Programming
a = i;
b = j;
}
class PassOb
{
public static void main(String args[])
{
Test ob1 = new Test(100, 22);
Test ob2 = new Test(100, 22);
Test ob3 = new Test(-1, -1);
System.out.println("ob1 == ob2: " + ob1.equals(ob2));
System.out.println("ob1 == ob3: " + ob1.equals(ob3));
}
}
Output:
ob1 == ob2: true
ob1 == ob3: false
In the above case, both b1 and b2 will be referring to same object, but not two different objects. So, we can write a
constructor having a parameter of same class type to clone an object.
class Box
{
double h, w, d;
void vol()
{
System.out.println("Volume is " + h*w*d);
}
public static void main(String args[])
{
Box b1=new Box(2,3,4);
Box b2=new Box(b1); //initialize b2 using b1
b1.vol();
b2.vol();
}
}
Output:
Volume is 24
Volume is 24
In Java, when you pass a primitive type to a method, it is passed by value. When you pass an object
to a method, they are passed by reference. Keep in mind that when you create a variable of a class type, you
are only creating a reference to an object. Thus, when you pass this reference to a method, the parameter that
receives it will refer to the same object as that referred to by the argument. This effectively means that objects are
passed to methods by use of call-by-reference. Changes to the object inside the method do affect the object used as
an argument.
class Test
{ int a, b;
Test(int i, int
j)
{
a = i;
b = j;
}
void meth(Test o)
{
o.a *= 2;
o.b /= 2;
}
}
class CallByRef
{
public static void main(String args[])
{
Output:
before call: 15 20
after call: 30 10
Test incrByTen()
{
Test temp = new Test(a+10);
return temp;
}
}
class RetOb
{
public static void main(String args[])
{
Test ob1 = new Test(2);
Test ob2;
ob2 = ob1.incrByTen();
System.out.println("ob1.a: " + ob1.a);
System.out.println("ob2.a: " + ob2.a);
ob2 = ob2.incrByTen();
System.out.println("ob2.a after second increase: " + ob2.a);
}
}
Output:
ob1.a: 2
ob2.a: 12
ob2.a after second increase: 22
3.15 Recursion
A method which invokes itself either directly or indirectly is called as recursive method. Every recursive method
should satisfy following constraints:
It should have at least one non-recursive terminating condition.
In every step, it should be nearer to the solution (that is, problem size must be decreasing)
class Factorial
{
int fact(int n)
{
if (n==0)
return 1;
return n*fact(n-1);
}
}
class FactDemo
{
public static void main(String args[])
{
Factorial f= new Factorial();
}
}
Output:
Factorial of 3 is 6
Factorial of 8 is 40320
Some aspects of access control are related to inheritance and package (a collection of related classes). The
protected specifier is applied only when inheritance is involved. So, we will now discuss about only private and
public.
When a member of a class is modified by the public specifier, then that member can be accessed by any other code.
When a member of a class is specified as private, then that member can only be accessed by other members of its
class. When no access specifier is used, then by default the member of a class is public within its own package, but
cannot be accessed outside of its package. Usually, you will want to
restrict access to the data members of a class—allowing access only through methods. Also, there will be times
when you will want to define methods that are private to a class. An access specifier precedes the rest of a
member’s type specification. For example,
public int x;
private char ch;
class Test
{ int a;
public int b;
private int c;
void setc(int i)
{
c = i;
}
int getc()
{
return c;
}
}
class AccessTest
{
public static void main(String args[])
{
Test ob = new Test();
ob.a = 10;
ob.b = 20;
// ob.c = 100; // inclusion of this line is Error!
ob.setc(100);
System.out.println("a, b, and c: " + ob.a + " " + ob.b + " "
+ ob.getc());
}
}
If you need to do computation in order to initialize your static variables, you can declare a static block that gets
executed exactly once, when the class is first loaded.
class UseStatic
{
static int a = 3;
static int b;
Output:
Static block initialized.
x = 42
a=3
b = 12
Outside of the class in which they are defined, static methods and variables can be used independently of any
object. To do so, you need only specify the name of their class followed by the dot operator. The general form is –
classname.method();
class StaticDemo
{
static int a = 42;
static int b = 99;
class StaticByName
{
public static void main(String args[])
{
StaticDemo.callme();
System.out.println("Inside main, b = " + StaticDemo.b);
}
}
Output:
Inside static method, a = 42
Inside main, b = 99
class Test
{
public static void main(String args[])
{
int a1[]=new int[10];
int a2[]={1, 2, 3, 4, 5};
int a3[]={3, 8, -2, 45, 9, 0, 23};
Output:
Length of a1 is 10
Length of a2 is 5
Length of a3 is 7
3.19 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
The previous program is an example of single inheritance.
Multilevel Inheritance: If several classes are inherited one after the other in a hierarchical
manner, it is known as multilevel inheritance, as shown below –
B
C
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 method overriding: Sometimes, we do not want a superclass method to be overridden in the
subclass. Instead, the same superclass method definition has to be used by every subclass. In such situation, we can
prefix a method with the keyword final as shown below –
class A
{
final void meth()
{
System.out.println("This is a final method.");
}
}
class B extends A
{
void meth() // ERROR! Can't override.
{
System.out.println("Illegal!");
}
}
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.
Question Bank:
1. Define class. Give syntax and example.
2. Briefly explain static members of the class with suitable examples.
3. Discuss method overloading. Write a program to overload a method area() to compute area of a triangle
and a circle.
4. Define a constructor. What are the salient features of Constructor? Write a Java program to show these
features.
5. How do you overload a constructor? Explain with a program.
6. Define recursion. Write a recursive program to find nth Fibonacci number.
7. Write a program to implement stack operations.
8. What are different parameter passing techniques in Java? Discuss the salient features of the same.
9. What are various access specifiers in Java? List out the behaviour of each of them.
10. Create a Java class called Student with the following details as variables (USN, Name, Branch, Phone
Number). Write a Java program to create n student objects and print USN, Name, Branch, and Phone
number with suitable heading.
11. What is inheritance? Discuss different types of inheritance with suitable example.
12. Discuss the behavior of constructors when there is a multilevel inheritance. Give appropriate code to
illustrate the process.
13. Mention and explain the uses of super keyword in Java.
14. How do you pass arguments to superclass constructor through the subclass constructor? Explain with a
code snippet.
15. Discuss usage of final keyword in Java. Give suitable examples.
16. What do you mean by method overriding? Discuss with a programming example.
17. Explain abstract class and abstract method with suitable code snippet.
18. Write a note on:
a. Use of this keyword
b. Garbage Collection in Java
c. Finalize() method
d. Object Class
e. Dynamic Method Dispatch
19. Create an abstract class called Employee. Include the members: Name, EmpID and an abstract method
cal_sal(). Create two inherited classes SoftwareEng (with the members basic and DA) and HardwareEng
(with members basic and TA). Implement runtime polymorphism (dynamic method dispatch) to display
salary of different employees by creating array of references to superclass.
20. Differentiate method overloading and method overriding.