Class Fundamental
Java is a true object oriented language and therefore the underlying structure of all Java program is classes. Anything we wish to represent in a Java program must be encapsulated in a class that defines the state and behavior of the basic program components known as objects. Classes create objects and objects use methods to communicate between them. That is all about object oriented programming.
Class: The class is at the core of Java. It is the logical construct upon which entire Java language is built because it defines the shape and nature of object. A class is a template that defines the form of an object. The class specifies both data and code that will operate on that data. Java uses a class specification to construct object. Thus, class is essentially a set of plans that specifies how to build an object.
It is important to be clear that a class is a logical abstraction. It is not until an object of that class has been created that a physical representation of that class exists in memory
Object: Object is an instance of the class. It is class variable. Because an object is instance of a class, we can use the two words objects and instances interchangeably.
Classes provide a convenient method for packing together a group of logically related data items and functions that work on them. In Java, the data items are called fields and the functions are methods. Calling a specific method in an object is described as sending the object a message.
Defining a Class
When we define a class, we declare its exact from and nature. This is done by specifying the data it contains and the code that operates on that data. A class is declared by use of keyword class. When we declare a class we specify data and code that operate on that data. The general form of a class definition is as shown below:
class classname {
type instance-variable1;
type instance-variable2;
…………………………………..
type instance-variableN;
type methodname1(parameter-list){
//Body of method
}
Type methodname2 (parameter-list){
//body of method
}
………………………………………………………….
type methodnameN(parameter-list){
//Body of method
}
}
Adding Variables
Data is encapsulated in a class by placing data fields inside the body of the class definition. These variables are called instance variables because they are created whenever an object of the class is instantiated. We can declare the instance variables exactly the same way as we declare local variables. Example:
class Rectangle
{
int length;
int width;
}
The class Rectangle contains two integer type instance variables. Instance variables are also known as member variables.
Adding Methods
A class with only data fields has no life. The objects created by manipulating the data contained in the class. Methods are declared inside the body of the class immediately after the declaration of instance variable.
The general form of a method declaration is:
type methodname(parameter_list)
{
Method –body;
}
Here type specifies the type of value the method return. This could be simple data type such as int as well as any class type. The method name is valid identifier. The parameter list is always enclosed in parenthesis. This list contains variable names and their types we want to give the method as input. The method body actually describes the operations to be performed on the data.
Creating Objects
An object in Java is essentially a block of memory that contains space to store all the instance variables. Creating an object is also referred to as instantiating an object.
Objects in Java are created using the new operator. The new operator creates an object of the specified class and returns a reference to that object. Here is an example of creating an object of type Rectangle.
Rectangle rect1; // declare
rect1 = new Rectangle ();
The first statement declares a variable to hold the object reference and second one actually assigns the object reference to variable.
Accessing Class Members
Outside the class, we cannot access the instance variables and the methods directly. To do this, we must use the concerned object and the dot operator as shown below:
objectname.variable name;
objectname.methodname (parameter_list);
The following program shows the class and its use.
class Rectangle{ int length; int width; void getData(int x, int y) { length = x; width = y; } int rectArea(){ return length*width; } } class RectArea{ public static void main (String args[]){ int area1,area2; Rectangle rect1 = new Rectangle(); Rectangle rect2 = new Rectangle(); rect1.length = 10; rect1.width = 5; area1 = rect1.length*rect1.width; rect2.getData (20,10); area2 = rect2.rectArea (); System.out.println ("Area = "+area1); System.out.println("Area = "+area2); } }
The output of the above program is
Area = 50
Area = 200
Reference Variables and Assignment
In an assignment operation, objects reference variables may act a bit differently than we expect. To explain clearly, let us consider what occurs when we assign one primitive type to another. Assuming two int variables called x and y, the statement x = y means that x receives a copy of the value contained in y. Thus, after the assignment, both x and y contain their own, independent copies of the value. Changing one does not affect the other.
When we assign one object reference variable to another, the situation is a bit more complicated because we are assigning references. This means that we are changing the object that the reference variable refers to, not making a copy of that object. The effect of this difference may seem counterintuitive
For example, consider the following fragment:
Rectangle r1 = new Rectangle();
Rectangle r2 = r1;
At first glance, it is easy to think that r1 and r2 refer to different objects, but this is not the case because no copy of the objects has been made. Instead r2 receives a copy of the reference in r1. As a result, r1 and r2 wil both refer to the same object. In other words, the assignment of r1 to r2 simply makes r2 refer to the same object as does r1.
Thus, after this assignment
r1.length = 10;
both the following statement will display the same value 10.
System.out.println (r1.lenngth);
System.out.println (r2.lenngth);
Although r1 and r2 both refer to the same object, they are not linked in any other way. For example, a subsequent assignment to r2 simply changes the object to which r2 refers. For example:
Rectangle r3 = new Rectangle ();
r2 = r3;
After this sequence, r2 refers to the same object as r3. The object referred to by r1 is unchanged.
Constructor
Java supports a special type of method, called a constructor that enables an object to initialize itself when it is created. Constructors have the same name as the class itself. Secondly, they do not specify a return type, not even void. This is because they return the instance of the class itself. The above program can be written as using constructor
class Rectangle{ int length; int width; Rectangle (int x,int y) { length = x; width = y; } int rectArea() { int area = length*width; return area; } } class RectArea{ public static void main (String args[]){ int area1; Rectangle rect1 = new Rectangle (30, 20); area1 = rect1.rectArea (); System.out.println ("Area = "+area1); } }
The output of above program is 600.
Methods Overloading
In Java, it is possible to create methods that have the same name, but different parameter lists and different definitions. This is called method overloading. Method overloading is used when objects are required to perform similar tasks but using different input parameter. When we call a method in an object. Java matches up the method name first and then the number and type of parameters to decide which one of the definitions to execute. This process is known as polymorphism. Here is an example of creating an overloaded method.
class Room{ float length; float breadth; Room(float x, float y){ length = x; breadth = y; } Room (float x){ length = breadth = x; } int area(){ return (length*breadth); } }
Static Members
Every time the class is instantiated, a new copy of each of instance variable and instance method is created. They are accessed using the objects with dot operator.
Let us assume that we want to define a member that is common to all the objects and accessed without using a particular object. That is, the member belongs to the class as a whole rather than the objects created from the class. Such members can be defined as follows:
static int count;
static int max(int x, int y);
The members that are declared static as shown above are called static members. Since these members are associated with the class itself rather than individual objects, the static variables and static methods are often referred to as class variables and class methods in order to distinguish them from their counterparts.
Static variables are used when we want to have a variable common to all instances of a class. One of the most common examples is to have a variable that could keep a count of how many objects of a class have been created. Java creates one copy for a static variable which can be used even if the class is never actually instantiated.
Like static variables, static methods can be called without using the objects. They are also available for use by other classes. For example, the Math class of Java class libraries defines a many static methods to perform math operations that can be used in any program.
We can define our own static methods as shown below:
class Mathoperation { static float mul(float x, float y) { return x*y; } static float divide(float x, float y) { return x/y; } } class MathApplication { public static void main(String args[]) { float a = Mathoperation.mul(4,5); float b = Mathoperation.divide(a,2); System.out.println("b = "+b); } }
The new Operator Revisited
class_var = new class-name (arg-list):
Here, class var is a variable of the class type being created. The class name is the name of the class that is being instantiated. The class name followed by a parenthesis argument list (which can be empty) specifies the constructor for the class. If a class does not define its own constructor, new will use the default constructor supplied by the Java. Thus, new can be used to create an object of any class type. The new operator returns a reference to the newly created object, which (in this case) is assigned to class-var.
Since memory is finite, it is possible that new will not be able to allocate memory for an object because insufficient memory exists. If this happens, a run time exception (will be discussed later) will occur.
The this keyword: When a method is called, it is automatically passed an implicit argument that is a reference to the invoking object (that is, the object on which the method is called). This reference is called this. To understand this, let us consider the following program.
class Power{ public double base; public double exp; public double val; public Power(double base,double exp){ this.base = base; this.exp = exp; this.val = 1; for(;exp>0;exp--)this.val = this.val*this.base; } public double getPower(){ return this.val; } } public class PowerDemo { public static void main(String[] args) { Power x = new Power(4,2); System.out.println(x.base+"raised to the "+x.exp+ " = "+x.val); } }
Actually, no Java programmer would write Power as just shown because nothing is gained, and the standard form is easier. However, this has some important uses. For example, the Java syntax permits the name of a parameter or a local name hides the instance variable. You can gain access to the hidden instance variable by referring to it through this.
Garbage Collection: As we that objects are dynamically allocated from a pool of free memory by using the new operator. Memory is not finite. and the free memory can be exhausted. Thus, it is possible for new to fail because there is insufficient free memory to create the desired object. For this reason, a key component of any dynamic allocation scheme is the recovery of free memory from unused objects, making that memory available for subsequent reallocation. C and C++ uses delete keyword to free memory that was already allocated. However, java uses a different, more trouble free approach: garbage collection.
Java’s garbage collection system reclaims objects automatically-occurring transparently, behind the scene, without any programmers intervention. It works like this: When no references to an object exist, that object is assumed to be no longer needed, and the memory occupied by the object is released. This recycled memory can then be used for a subsequent allocation.
Garbage collection occurs only sporadically during the execution of program. It will not occur simply because one or more objects exist that are no longer used. For efficiency, the garbage collector will usually run only when there is need to recycle them. The Java Run time system does it only when it is appropriate. Thus, we cannot know precisely when garbage collection will not take place.
The finalize () Method: It is possible to define a method called finalizer that will be called just before an object’s final destruction by the garbage collector. This method is called finalizer (), and it can be used in very specialized cases to ensure that an object terminates cleanly. For example, finalize() method might be used to make sure that some system resource not managed by the Java run time is properly released. Although the vast majority of Java programs do not need finalizer, the topic is covered here for completeness and because a finalizer will be used to demonstrate Java’s garbage collection mechanism.
To add a finalizer to a class, we must define the finalize() method. The Java run time system calls that method whenever it is about to recycle an object of that class. Inside the finalize () method we will specify those actions that must be performed before an object is destroyed.
The finalize() method has this form:
protected void finalize()
{
// Finalization code here
}
It is important to understand that finalize() is used just before garbage collection. It is not called when an object goes out of scope.
Consider the following code;
public class GarbageColection { protected void finalize(){ System.out.println("Object destroyed"); } public static void main(String [] args){ GarbageColection g = new GarbageColection(); g.finalize (); g = null; System.gc (); } }
The output of the above method is :
Object destroyed;
Object destroyed;
A Stack class
A stack is a list in which elements can be accessed in the last in , first out(LIFO) order only. In general, stacks support two basic operations, traditionally called push and pop. Each push operation puts a new element on the top of the stack. Each pop operation retrieves the top element from the stack. Thus, a new element is added to the stack by putting it on the top, and an element is removed from the stack by taking it off the top. No other access to stack’s element is supported. For example, we can’t remove an element from the middle of a stack. Furthermore, popping an element from the stack consumes that element. In other words, once an element has been retrieved, it cannot be retrieved again.
A stack has two boundary conditions: full and empty. A stack is full when there is no space available to store another item. It is empty when all of its elements have been removed.
The following program explains stack
class Stack { public char[] data; public int tos; public Stack(int size){ data = new char[size]; tos = 0; } public void push(char ch){ if(isFull()){ System.out.println("------Stack Full......."); return; } data[tos++]=ch; } public char pop(){ if(isEmpty()){ System.out.println("----- Stack is empty"); return (char)0; } return data[--tos]; } public boolean isEmpty(){ return tos==0; } public boolean isFull(){ return tos == data.length; } } public class StackDemo { public static void main(String[] args) { int i; char ch; System.out.println("Demonstartes simple stack"); Stack stk = new Stackk(10); System.out.println("Push 10 items onto a 10 element stack"); System.out.println("Pushing "); for(ch='A';ch<'K';ch++){ System.out.print(ch+"->"); stk.push(ch); } System.out.println("\nPop 10 items from stack "); System.out.println("Popping: "); for(i=0;i<10;i++){ ch = stk.pop(); System.out.println (ch+" ->"); } } }
The output of the above program is:
Demonstrates simple stack
Push 10 items onto a 10 element stack
Pushing
A->B->C->D->E->F->G->H->I->J->
Pop 10 items from stack
Popping:
J ->I ->H ->G ->F ->E ->D ->C ->B ->A ->