Showing posts with label java concepts. Show all posts
Showing posts with label java concepts. Show all posts

Saturday, 30 May 2015

Java Inheritance

Inheritance is a mechanism to inherit the properties of a class in another class. In the terminology of java, a class that is inherited is called a super-class or base-class or parent class. The class that does the inheriting is called a sub-class or child-class or derived class.

Inheritance allows us to extend an existing class (base class) by adding additional features to it as discussed earlier. It encourages the code reusability, which helps in reducing the code size although it may lead to complexity in some cases.

If a built-in class provides most of the needed functionality except one or two features then we
have two alternatives: (i) rewriting the class, and (ii) extending the class.  In most of the cases, second alternative will be a better choice, as we have to write only small piece of code. At the same time we won’t have to spend much time in debugging and testing as the base class is already tested and is in use for a long period of time.

Moreover it is possible that we do not have access to the source code of an existing class as someone else has developed it and what we have is only the class file. So the only way to add new feature is by extending the class to derive a new class with added features. We would not like to modify the existing class even if the source code is available as it might be in use in many other classes and changes to it may affect the other classes using it.

Java Recursive Methods

This feature is not specific to object-oriented languages. The concept is exactly same as in case of a procedural language. Using this feature a method can call itself.

Example: The following programs make use of the recursive method fact to calculate the factorial of a given positive integer.

1 class Factorial

2 { long fact (int n)

3 { if(n == 1)

4 return 1;

5 else

6 return n*fact(n-1);

7 }

8 public static void main(String args[])

9 { Factorial f=new Factorial();

10 System.out.println("Factorial of 4 = "+f.fact(4));

11 }

12 }

1 class Factorial

2 { static long fact (int n)

3 { if(n == 1)

4 return 1;

5 else

6 return n*fact(n-1);

7 }

8 public static void main(String args[])

9 { System.out.println("Factorial of 4 = "+fact(4));

10 }

11 }

Java Argument Passing Mechanism (call by value)

When a primitive type is passed to a method, it is done by use of call-by-value approach. In case of objects what is actually passed is an object reference. As a point of interest, an object reference is also passed by using call-by-value approach. However, since the value being passed refers to an object, the copy of that value will still refer to the same object that its corresponding argument does.

Example: The following example illustrates that Java uses call-by-value when passing primitive data types.

1 class Args1

2 { void swap(int a, int b)

3 { int t= a;

4 a = b; b = t;

5 }

6 public static void main(String args[])

7 { int x = 5, y = 7;

8 System.out.println("x = " + x + " y = " + y);

9 Args1 obj = new Args1(); obj.swap(x,y);

10 System.out.println("x = " + x + " y = " + y);

11 }

12 }

Output:

x = 5 y = 7

x = 5 y = 7

Example: The following example also illustrates that Java uses call-by-value when passing primitive data types.

1 class Args2

2 { static void swap(int a, int b)

3 { int t= a;

4 a = b; b = t;

5 }

6 public static void main(String args[])

7 { int x = 5, y = 7;

8 System.out.println("x = " + x + " y = " + y);

9 //Args2.swap(x,y);

10 swap(x,y);

11 System.out.println("x = " + x + " y = " + y);

12 }

13 }

Output:

x = 5 y = 7

x = 5 y = 7

Example: The following example illustrates that Java uses call-by-value even when passing reference types.

1 class Args3

2 { int a,b;

3 Args3(int x, int y)

4 { a = x;

5 b = y;

6 }

7 static void swap(Args3 ob1, Args3 ob2)

8 { Args3 t;

9 t = ob1;

10 ob1 = ob2;

11 ob2 = t;

12 }

13 public static void main(String args[])

14 { Args3  obj1 = new Args3(5,7);

15 Args3  obj2 = new Args3(4,6);

16 System.out.print("obj1.a = " + obj1.a + " obj1.b = " + obj1.b);

17 System.out.println(" obj2.a = " + obj2.a + " obj2.b = " + obj2.b);

18 swap(obj1,obj2);

19 System.out.print("obj1.a = " + obj1.a + " obj1.b = " + obj1.b);

20 System.out.println(" obj2.a = " + obj2.a + " obj2.b = " + obj2.b);

21 }

22 }

Output:

obj1.a = 5 obj1.b = 7 obj2.a = 4 obj2.b = 6

obj1.a = 5 obj1.b = 7 obj2.a = 4 obj2.b = 6

Example: The following example illustrates that although Java uses call-by-value when passing reference types but we can still modify the object referred to by the argument inside the called method, as what is actually passed is a reference.

1 class Args4

2 { int a,b;

3 Args4(int x, int y)

4 { a = x;

5 b = y;

6 }

7 static void swap(Args4 ob1, Args4 ob2)

8 { int x,y;

9 x = ob1.a; y = ob1.b; ob1.a = ob2.a; ob1.b = ob2.b;

10 ob2.a = x; ob2.b = y;

11 }

12 public static void main(String args[])

13 { Args4  obj1 = new Args4(5,7);

14 Args4  obj2 = new Args4(4,6);

15 System.out.print("obj1.a = " + obj1.a + " obj1.b = " + obj1.b);

16 System.out.println(" obj2.a = " + obj2.a + " obj2.b = " + obj2.b);

17 swap(obj1,obj2);

18 System.out.print("obj1.a = " + obj1.a + " obj1.b = " + obj1.b);

19 System.out.println(" obj2.a = " + obj2.a + " obj2.b = " + obj2.b);

20 }

21 }

Output:

obj1.a = 5 obj1.b = 7 obj2.a = 4 obj2.b = 6

obj1.a = 4 obj1.b = 6 obj2.a = 5 obj2.b = 7

Java Variables

Java has three kinds of variables:


  • Local variables
  • Instance variables
  • Static Variables


We have already discussed about local variables. Local variables are used inside blocks or methods. The other two types of variables (also referred to as data members) are defined within the class but outside any method/block.

1. Instance Variables

A class provides the data encapsulation by declaring the variables within the class definition. For example, in the class Box defined above, the variables width, height and length are instance variables. Instance variables are declared in the same way as local variables except that they are declared outside the methods.

An instance variable occupies the memory on the per-object basis. For example, if you create two objects of type Box using operator new then both the objects will have different set of variables corresponding to instance variables width, height and length.

Initialization

The instance variables are initialized as soon as the object is created i.e. as soon as the memory is allocated with the new operator. The variables are initialized according to their types as shown in
the following tables.

For example, as soon as an object of type Box is created, the instance variables width, height and

length are initialized to 0 (Zero).

Accessing Instance Variables

The dot (.) operator is used to access the instance variables. The general form for accessing the
instance variables using the dot operator is:

<Object Reference>.<Variable Name>

Where <Object Reference> is some reference variable pointing to an object and <Variable
Name> is the name of an instance variable. For example, after creating an object of type Box and
storing its reference in the reference variable box, we can access the instance variables using dot
operator as follows:

box.width box.height box.length

Thus the way of accessing instance variables is very similar to the way in which we access the
members of structures in C or C++. But there is one significant difference. In C/C++, we can
access structure members directly as well as through pointers. But in Java program, we never
have access to an object directly. We always access an object through its reference. Thus the dot
(.) operator of Java is like -> operator of C/C++.

We can assign values to instance variables just like local variables as shown below:

box.width = 10; box.height = 20; box.length = 30;

We can use instance variables in expressions as shown below:

double vol =  box.width * box.height * box.length;

We can display the values of the instance variables, just like local variables as shown below:

System.out.println(box.height);

Example: The following program demonstrates the concepts discussed till now.

1 class Box

2 { double width;

3 double height;

4 double depth;

5 public static void main(String args[])

6   { Box b = new Box();

7 double vol;

8 b.width = 10;

9 b.height = 20;

10 b.depth = 15;

11 vol = b.width * b.height * b.depth;

12 System.out.println("volume is " + vol);

13 }

14 }

Example: The following program provides the same functionality as the previous one but it uses
two classes: Box and BoxDemo. Here it is assumed that both the classes are defined in different
files: Box.java and BoxDemo.java. It is also possible to define both the Java classes in one file.

Box.java

1 class Box

2 { double width;

3 double height;

4 double depth;

5 }

BoxDemo.java

1 class BoxDemo

2 { public static void main(String args[])

3    { Box b = new Box();

4 double vol;

5 b.width = 10;

6 b.height = 20;

7 b.depth = 15;

8 vol = b.width * b.height * b.depth;

9 System.out.println("volume is " + vol);

10  }

11 }

Compiling Box.java will generate Box.class file and compiling BoxDemo.java will generate
BoxDemo.class file. After compiling these two files you should run the BoxDemo class, because
it contains the main() method.
It is not necessary for both the Box and BoxDemo classes to be in the different source file. For
example, both the classes might be defined in the source file Box.java but compiling this file will
also generate two different classes: Box.class and BoxDemo.class.

Example: The pervious example is modified so that the classes Box.java and BoxDemo.java
belong to the package p1.

Box.java

1 package p1;

2 class Box

3 { double width;

4 double height;

5 double depth;

6 }

BoxDemo.java

1 package p1;

2 class BoxDemo

3 { public static void main(String args[])

4 { Box b = new Box();

5 double vol;

6 b.width = 10;

7 b.height = 20;

8 b.depth = 15;

9 vol = b.width * b.height * b.depth;

10 System.out.println("volume is " + vol);

11 }

12 }

To run the above program you should put both the classes in folder p1 in the working folder and
then give the following command from the working folder (parent of p1):

java p1.BoxDemo

The folder p1 will be created automatically (if it does not exist), in the working folder, if you
compile the above java files using the command:

javac  -d . Box.java

javac  -d . BoxDemo.java

Example: The pervious example is modified so that the classes Box.java and BoxDemo.java
belong to package p1 and p2 respectively.

Box.java

1 package p1;

2 public class Box

3 { public double width; //instance variables

4 public double height;

5 public double depth;

6 }

BoxDemo.java

1 package p2;

2 import p1.*;

3 class BoxDemo

4 { public static void main(String args[])

5    { Box b = new Box();

6 double vol;

7 b.width = 10; b.height = 20; b.depth = 15;

8 vol = b.width * b.height * b.depth;

9 System.out.println("volume is " + vol);

10   }

11 }

The folder p1 and p2 will be created automatically (if do not exist), in the working folder, if you
compile the above java files using the commands:

javac  -d . Box.java

javac  -d . BoxDemo.java

To run the above program you should give the following command from the working folder

(parent of p1 and p2):

java  p2.BoxDemo

Note that the class Box is declared public as it used in class BoxDemo that belongs to a different
package.  Similarly all the data members of the class Box are also declared public as they are
being accessed in class BoxDemo.

Also note that the class BoxDemo imports class Box so that it can use the class without
qualifying with the package name.

Example: Creating two instances of Box class
If you have two Box objects, each has its own copy of depth, width, and height. It is important to
understand that changes to the instance variables of one object have no effect on the instance
variables of another.

Box.java

1 class Box

2 { double width; //instance variables

3 double height;

4 double depth;

5 }

BoxDemo2.java

1 class BoxDemo2

2 { public static void main(String args[])

3  { Box b1 = new Box();

4 Box b2 = new Box();

5 double vol;

6 b1.width = 10;

7 b1.height = 20;

8 b1.depth = 15;

9 b2.width = 3;

10 b2.height = 6;

11 b2.depth = 9;

12 vol = b1.width * b1.height * b1.depth;

13 System.out.println("volume is " + vol);

14 vol = b2.width * b2.height * b2.depth;

15 System.out.println("volume is " + vol);

16    }

17 }

2. Static Variables

Static variables are also declared outside methods/blocks like instance variables. But the static
variables make use of the modifier static before the data type. For example, the variable width in
the previous example can be made static variable if declared as:

static double width;

The static variables are global to a class and all of its instances (objects). They are useful for
keeping track of global states. For example, a static variable count in a class can store the
number of instances/objects of the class created in the program at any instance of time. The
objects can communicate using static variables just like C functions communicate through global
variables.

For static variables there is only one copy of the variable irrespective of number of instances/objects created in the program, which is shared across all the instances.

The dot (.) operator is used to access the static variables also. The general form for accessing the static variables using the dot operator is:

<Class Name>.<Variable Name>

Where <Class Name> refers to the name of the class in which the static variable is declared and
<Variable Name> is the name of a static variable. For example, if we declare the variables width,
height and depth as static then we can access them using dot operator as follows:

Box.width

Box.height

Box.length

We can also access the static variables through object reference and dot operator as follows but any reference will point to the same copy:

box.width

box.height

box.length

Example: The following example illustrates that for static variables there is only one copy of the
variable irrespective of number of instances/objects created in the program, which is shared across all the instances.

Initialization

The static variables are initialized as soon as the class is loaded/used. The variables are initialized with default values according to their types. The default values are same as those for instance variables.

Box.java

1 class Box

2 { static double width;

3 static double height;

4 static double depth;

5 }

BoxDemo.java

1 class BoxDemo3

2 { public static void main(String args[])

3    { Box b1 = new Box();

4 Box b2 = new Box();

5 double vol;

6 b1.width = 10;

7 b1.height = 20;

8 b1.depth = 15;

9

10 b2.width = 3;

11 b2.height = 6;

12 b2.depth = 9;

13 vol = b1.width * b1.height * b1.depth;

14 System.out.println("volume is " + vol);

15 vol = b2.width * b2.height * b2.depth;

16 System.out.println("volume is " + vol);

17  }

18 }

Java Declaring Objects

You can declare object of class Box as follows:

Box box;

Normally we say that box is an object of type Box. This is correct in C++ but this is not fully correct in Java. Because box is simply a variable that can hold reference to an object of type Box.

This is like pointer to a structure in C/C++. The reference box will store garbage or null reference unless we assign reference of some object of class Box to it.

After the above declaration variable box will contain garbage or null reference as shown below:

This indicates that variable box is not pointing to any object.

If the variable box is defined in a method or block it will contain garbage, as local variables are not initialized by default. To make sure that it contains null unless some valid reference (conceptually same as pointer of C/C++) is assigned to it, you must declare and initialize the box as follows:

Box box = null;

If the above declaration of box is outside any method/block then it is an instance variable and there is no need not initialize it with null as an instance/reference variables are always initialized with null.

Java Access/Visibility Modifiers

Access/visibility modifiers control access to a class, interface, data member or method. There are four levels of visibility in Java:


  • public
  • protected
  • package
  • private

1. Access/Visibility Modifiers for Top-Level Classes.

Visibility of a top-level class can be either public or package.

public

The keyword public is the only modifier, which can be used with a top-level class. If a class is to 
be visible to all the classes irrespective of their package, then it must be declared as public by specifying the modifier public, which should appear before the keyword class.

package

There is no keyword package for visibility control. In the absence of any access/visibility modifier before the top-level class, its visibility is only within the package in which it is defined. The concept of package is somewhat similar to the concept of friend classes in C++.

2. Access/Visibility Modifiers for Data Members and Methods.

When used in the variable or method declarations, access/visibility modifiers control access to the variable or method i.e. they decide who can access the variables and methods. These modifiers are not applicable for local variables as their visibility/scope is anyhow limited to the method/block in which they are declared.

public

Any method or variable is always visible in the class in which it is declared. The instance methods of a class can access any other method (instance as well as static method) or variable (instance as well as static variable) declared in the class. Similarly a static method of a class can access any other static method or static variable declared in the same class. 

If a method or variable is to be visible to all the classes, then it must be declared as public by specifying the modifier public, which should appear before the data type. For example, main() method is always declared as public. The reason is that main() method is accessed by the code which is part of JVM i.e. it is outside the class in which main() method is declared. Similarly an instance or static variable can be declared public by specifying modifier public as shown below:

public float width;
public static float width;

A variable or method declared as public has the widest possible visibility. It can be accessed from any class.

private

If you want that a method or variable should not be visible outside the class in which it is declared then its access modifier should be private. We use this modifier to hide the variable or method so that it cannot be accessed from outside the class. 

A variable declared as private has the least possible visibility but it is the most commonly used modifier to encourage data encapsulation and data hiding.  

package 

There is no keyword package. In the absence of any access/visibility modifier before a data member or method, its visibility is only within the package in which it is defined.

protected

A variable declared as protected can be accessed from all the classes belonging to the same package as that of the class in which member is declared. This visibility is similar to the package scope. But in addition to this a protected member can be accessed from any child class irrespective of the package in which it is declared.

Example: A simple class Box is defined below.

1 class Box
2 {
3    double width;
4    double height;
5    double length;
6 }

Example: The class Box is redefined here to include one method volume().

1 class Box
2 {
3    double width;
4    double height;
5    double length;
6    void volume()
7    {
8        double vol = width * height * length;
9        System.out.println(vol);
10  }
11 }

Java defining a class

A Java class represents a user-defined data type. It acts like a template using which we can create multiple objects. The objects are like variables /instances of the data type represented by the class. To begin with you can think of a class as struct of C with the difference that a struct data type can have only data as members whereas the class can have data as well as methods as its members.

The general form of a class is

modifiers class <classname>
{
      <body of the class>
}

The body of the class can consist of data members as well as methods.
The general form is expanded below to show the fact that the class body can contain data members (variables) as well as methods.

modifiers class <classname>
{
modifiers type variable1;
modifiers type variable2;
.

.

modifiers type methodname1(parameter-list)
{
     <body of the method>
}

modifiers type methodname2(parameter-list)
{
     <body of the method>
}

.

.

}

Friday, 29 May 2015

Basic Concepts of OOP (Object-Oriented Programming)

Some of the essential elements of the object-oriented programming are mentioned below:


  • Abstraction
  • Objects and Classes
  • Three OOP Principle
                   Encapsulation
                   Inheritance
                   Polymorphism

  • Persistence
  • Genericity
  • Composition/Aggregation
1. Abstraction

The abstraction is one of the essential elements of any programming language including the procedural languages. The concept of built-in data type is also an abstraction. The feature of defining own data type using struct in C language further extends this abstraction.

The basic purpose of abstraction is to reduce complexity by hiding details. For example, people do not think of car as a set of hundreds of components. They think of it as a well-defined object having some unique properties and behavior.

Abstraction can be defined as an act for identifying the essential properties and behaviors of an object without going into details. The properties and behaviors of an object differentiate it from other objects of similar type and also help in classifying/grouping the objects.

The object-oriented programming languages model abstractions using classes and objects.

2. Objects and Classes

Object

An object is a physical or abstract entity or thing, which can be distinguished from other objects of similar types. An object has three characteristics:

(i) Identification
(ii) Properties (Attributes)
(iii) Behaviors (Methods/Operations/Functions)

The object can also be thought of as an instance of class, where class is like a built-in data type and object is a variable.

Class

A class represents a category of objects with similar properties and behaviors. A class can be thought of as a blueprint for creating objects. An object has the properties and behaviors defined by its class. The class can be thought of as a user-defined data type and object as a variable/instance of the data type represented by the class.

The properties/attributes of an object are defined by data members/fields in Java. A data member/field in a class is a variable that can hold data. The behaviors/operations of an object are defined using methods in Java. Both data members and methods are referred to as members of the class.

A class may also be thought of as a user-defined data type and an object as a variable of that data type. Once a class has been defined we can create any number of objects belonging to that class.

3. Three OOP Principles

3.1 Encapsulation

Encapsulation is the mechanism that binds code and data on which the code acts. Java classes support this as they allow us to define the code and data together. Encapsulation also helps in achieving data hiding by declaring some of the class members as private so that they cannot be accessed from the code that does not belong to the class.

3.2 Inheritance

In object-oriented programming, inheritance refers to the properties of a class being available to other classes called sub-classes or derived-classes. A sub-class or derived class is one that is derived from an existing class. It inherits all the features of the existing class which is also referred as the base-class or super-class. So inheritance can be defined as the process of deriving a class from a super-class or a base-class. Inheriting a class does not introduce any changes in the base-class/super-class. The derived-class/sub-class has a larger set of properties and behaviors as compared to the base-class.

The major advantage of the inheritance is code reusability. If the base class is in use for a long time and there is a need to add some extra attributes and methods, we can do so by deriving another class. The derived class will be able to use code of the base class without debugging as it is in use for a long time

Class Hierarchy

All the classes derived from a common base class belong to a family and form a class hierarchy. The class hierarchy can be compared with a tree structure where one base class is at the root and does not have a super-class. All other classes are either derived from the class at the root of the hierarchy or from some other class, which is derived from the root class directly or indirectly.

More features are added as we go down the tree. The classes that are represented by the leaf nodes do not have any sub-classes. The following examples show some class hierarchies.

Example 1: You can derive classes Saving Account and Current Account from the class Account. Here Account is the Base/Super Class and Saving Account and Current Account are Derived/Sub classes.

Example 2: The following diagram shows the classes derived from the Base class Vehicle.

3.3 Polymorphism

Polymorphism is a feature that allows same interface to be used for a general class of actions.

Most of the object-oriented languages use polymorphism in the following situations:

  • Operator Overloading
  • Method Overloading
  • Method Overriding

Operator Overloading

Most of the languages use this form of polymorphism for the built-in operations. For example, all the arithmetic operators in C/C++ or Java can be used with many types of operands (int, long, float, double etc.). So same addition operator can be used to add two integers as well as to add

two floating-point numbers. 

The C++ allows the user to overload the built-in operators. For example, you can overload the 

arithmetic operators to handle the complex numbers also. Although Java uses operator 

overloading for built-in operators but does not allow the user to overload the operators.

Method Overloading

This feature allows us to write more than one methods with the same name. Both C++ and Java have this feature. The methods (functions in C++) with same name are differentiated based on the parameters. The overloaded methods must either have different number of parameters or the types of the parameters must differ if their number is same.

If the call to an overloaded method can be resolved at compile time i.e. if the compiler can decide which of the overloaded method will be called then this is called static binding, which is an example of compile time polymorphism. 

If the call to an overloaded method cannot be resolved at compile time i.e. if the compiler cannot 
decide which of the overloaded method will be called then this is called dynamic binding, which 
is an example of run-time polymorphism. 

In general Java resolves calls to overloaded methods at run-time but there are many situations 
where the calls to overloaded methods are resolved at compile-time.

Method Overriding

The sub-class can define a method with the same name as in the super-class, and same number and type of parameters. This is called method overriding. 

The compiler can not resolve call to an overridden method. Java normally uses dynamic binding to resolve calls to overridden methods i.e. the decision takes place at run-time.

4. Persistence

Some object-oriented languages allow you to store/retrieve the state of a program to/from a persistent storage media i.e. a permanent storage media like secondary storage. This is called persistence.

Java allows you to store any object on the secondary storage and to retrieve it later on. If you attempt to store an object at the top of an object graph, all of the other referenced objects are recursively located and saved. Similarly when the object is retrieved later on, all of the objects and their references i.e. the entire object graph is correctly created in the main memory.

For example, it is possible to save an entire tree structure by just saving the root of the tree. At a
later stage it is possible to recreate the entire tree structure in the memory by just retrieving the root.
The C++ does not support this feature.

5. Genericity

The concept of defining an algorithm once, independently of any specific type of data, and then 
applying that algorithm to a wide variety of data types without any additional effort is called Genericity. 

C++ supports this feature using templates. Java also supports this feature through Object class, 
which is at the top of any class hierarchy in Java.

For example, using this feature, we can implement a generic data type stack so that it is possible 
to store element of any type in the stack.

This feature increases the degree of reusability to a large extent.

6. Composition/Aggregation

An object might be made up of other objects. Such an object is called Composite or Aggregate 
object. For example, it is appropriate if an object of class vehicle is defined as a composite object 
made up of objects like Engine, Body, Axle, Seats etc.

Inheritance v/s Composition

There are two basic mechanisms for deriving new classes from the existing ones: Inheritance and 
Composition. 

The class Bus can be derived by inheriting properties of class vehicle. Here Bus is a kind of vehicle which has some additional properties / behaviors beside the properties and behaviors which are common for all the vehicles. In other words class Bus has is-a relationship with the class vehicle as we can say that Bus is a vehicle.

The class vehicle itself might be derived from many other classes using composition. For example, an object of class vehicle might be composed of objects belonging to classes like Engine, Gear Box, Seats, Driver’s Seat, Body, Steering Wheel etc. The derived class in this case has whole-part relationship with the classes representing parts of the composite object. We can not say that Vehicle is an Engine or Vehicle is a Gear Box as Vehicle is made up of a number of parts.