Thursday, 4 June 2015

Java implementing an Interface

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 simplest form of a class implementing an interface is:

modifiers class <class-name> implements <interface-name>

{

body of the class

}

The body of the class must provide implementations of the methods declared in the interface.

You can also add additional features in the implementing class.

The methods that implement an interface must be declared public. Also, the signature of the implementing methods must match exactly the signature specified in the interface definition.

Java does not support multiple-inheritance but it supports multiple interface inheritance i.e. a class can implement any number of interfaces as shown below:

modifiers class <class-name> implements <interface-1>, <interface-2>, ……..<interface-n>

{

body of the class

}

The implementing class must provide body of all the methods in all the interfaces otherwise it must be declared as abstract.

The implementing class may also extend a class and can implement multiple interfaces. The most general form of a class that includes the implements clause looks like this:

modifiers class className [extends super-class] [implements interface1, interface2...]

{

class-body

}

Example:

interface Callback

{

void callback(int x);

}

Following is an implementation of the Callback interface

class Client1 implements Callback

{ public void callback(int x)

{ System.out.println(“Client1: ”+x);

}

}

Notice that callback method is declared using public access specifier. When you implement an interface method, it must be declared as public. The implementing an interface method is like over-riding so we cannot decrease the visibility.

1. Non Interface Methods

It is both permissible and common for classes that implement interfaces to define additional members of their own. For example, the following version of client implements callback() and adds the method m1():

class Client2 implements Callback

{ public void callback(int x)

{ System.out.println("Cleint2: " + 2*x);

}

public void m1()

{ System.out.println("m1 of Client2");

}

}

2. Accessing Implementations through Interface References

You can declare variables as object references that use an interface rather than a class type. Any instance of any class that implements the declared interface can be referred to by such a variable.

When you call a method through one of these references, the correct version will be called based on the actual instance of the interface being referred to. This is one of the key features of interfaces.

The method to be executed is looked up dynamically at run time, allowing classes to be created later than the code, which calls methods on them. The calling code can dispatch through an interface without having to know anything about the “callee”. This process is similar to using a super class reference to access a sub class object.

Note: Because dynamic lookup of a method at run time incurs a significant overhead when compared with the normal method invocation in Java, you should be careful not to use interface casually in performance-critical code.

Example: The following example demonstrates invoking method via an interface reference variable:

interface Callback

{ void callback(int x);

}

class Client1 implements Callback

{ public void callback(int x)

{ System.out.println("Client1: "+x);

}

}

class Client2 implements Callback

{ public void callback(int x)

{ System.out.println("Cleint2: " + 2*x);

}

public void m1()

{ System.out.println("m1 of Client2");

}

}

class InterfaceDemo1 //Accessing implementation through interface

{ public static void main(String args[])

{ Callback c = new Client1();

c.callback(10);

Callback c1 = new Client2();

c1.callback(10);

//c1.m1();

Client2 c2 = (Client2)c1;

c2.m1();

}

}

Output:

Client1: 10

Cleint2: 20

m1 of Client2

Notice that variable c is declared to be of interface type Callback, yet it is assigned an instance of Client1.

Although c1 can be used to access the callback() method, it cannot access any other members of the class Client2. An interface reference variable only has knowledge of the methods declared by its interface declaration.

Thus, c1 could not be used to access m1() method since it is defined by Client2 but not by Callback interface.

3. Polymorphic Power of Interface Reference Variable

The following example demonstrates the Polymorphic power of interface reference variable:

class InterfaceDemo2 //Polymorphic power of interface reference

{ public static void main(String args[])

{ Callback c;

Client1 c1  = new Client1();

Client2 c2  = new Client2();

c = c1;

c.callback(10);

c = c2;

c.callback(10);

}

}

Output:

Client1: 10
Cleint2: 20

4. Partial Implementation

If a class implements an interface but does not fully implement the methods defined by that interface, then that class must be declared as abstract.

Example:

abstract class Incomplete implements Callback

{ private int x;

void show()

{ System.out.println(x);

}

}

Here, the class Incomplete does not implement callback() method and must be declared as abstract. Any class that inherits Incomplete must implement callback() or be declared abstract itself.

Java defining an Interface

The general form of an interface is like class as shown below.

modifiers interface <interfac_name>

{ modifiers return_type method1(parameter-list);

modifiers return_type method2(parameter-list);

.

modifiers type final_var1 = value1;

modifiers type final_var2 = value2;

.

}

1. Modifiers for Top-Level Interface

The only modifiers that can be used with the top-level interfaces are abstract and public.

Even if we do not use abstract modifier, the interface is implicitly declared to be abstract so use of modifier abstract is redundant.

The visibility of a top-level interface can be either package or public just like top-level class. If no visibility modifier is used then the visibility of the interface is assumed to be package.

2. Interface Methods

Methods declared in an interface have no body. They end with a semicolon after the parameter list. They are, essentially, abstract methods and there can be no default implementation of any method specified within an interface.

All the methods declared in an interface have two modifiers, which are implicit:

abstract public method(parameter-list);

Methods are always abstract, which means they do not have any body and have public access.

All the methods declared in an interface are instance methods to be defined in the sub-classes.

We cannot declare static methods in interfaces.

3. Interface Data Members

We can define only constants in the interfaces.  All the variables in an interface are implicitly public, final and static meaning they cannot be changed by the implementing class. They must also be initialized with constant value.

Variables in an interface have implicit modifiers as shown below:

public static final int x = 10;

The variable x is public, static and final. It means it is a static variable with public access. The variable is also declared final, which means that it must be assigned a value at the time of declaration, which cannot be modified later on. The keyword final is like const in C/C++.

Example: The following program defines an interface for a stack i.e. it abstracts the public part of the stack.

interface StackInterface

{ void push(int x);

int pop();

}

The interface specifies that the stack has just two operations and any class sub-classing (implementing) this interface must provide bodies of push() and pop() methods.

Java Interface introduction

The purpose of the interface is to separate a class’s interface from its implementation. Interface just defines what a class must do without saying anything about the implementation. Interfaces define only method signatures and they do not have any instance variables. Interfaces are very good tool for designing as you can just define signatures of public methods without going into
implementation details, which are left for the person implementing the interface.

Using the keyword interface, you can fully abstract a class‘s interface from its implementation. That is, using interface, you can specify what a class must do, but not how it does it.

Interfaces are syntactically similar to classes, but they lack instance variables, and their methods are declared without any body. In practice, this means that you can define interfaces, which do not make assumptions about how they are implemented. Once it is defined, any number of classes can implement an interface. Also, one class can implement any number of interfaces.

To implement an interface, a class must create the complete set of methods defined by the interface. However, each class is free to determine the details of its own implementation. By providing the interface keyword, Java allows you to fully utilize the “one interface, multiple methods” aspect of polymorphism.

Interfaces are designed to support dynamic method resolution at run time. They disconnect the definition of a method or set of methods from the inheritance hierarchy. Since interfaces are in a different hierarchy from classes, it is possible for classes that are unrelated in terms of class hierarchy to implement the same interface. This is where the real power of interfaces is realized.

Note: Interfaces add most of the functionality that is required for many applications, which would normally resort to using multiple inheritance in a language such as C++.

Sunday, 31 May 2015

Java Importing packages

We discuss this concept with reference to previous example. Given that packages exist and are a good mechanism for compartmentalizing diverse classes from each other, it is easy to see why all of the built in Java classes are stored in packages.

There are no core java classes in the unnamed default package; all of the standard classes are stored in some named package.

Since classes within packages must be fully qualified with their package name or names, it could become tedious to type the long dot-separated package path name for every class you want to use. For this reason, Java includes the import statement to bring certain classes, or entire package into visibility. Once imported, a class can be referred to directly, using only its name.

Note: The import statement is a convenience to the programmer and is not technically needed to write a complete Java program. If you are going to refer to a few dozen classes in your application, however, the import statement will save a lot of typing.

In Java source file, import statements occur immediately following the package statement. (if it exists) and before any class/interface definitions.

The geneal form of import statement:

import pkg1 [.pkg2] [.pkg3].[classname | *];

Note: 

1. The star form may increase compilation time. However, the star form has absolutely no effect on the run-time performance or size of your classes.

2. All of the standard Java classes included with Java are stored in a package called java. The basic language functionality is stored in a package inside of the java package called java.lang. Normally, you have to import every package or class that you want to use, but since Java is useless without much of the functionalities in java.lang, it is implicitly imported by the compiler for all programs. This is equivalent to the following line being at the top of all of your programs:

import java.lang.*;

3. If a class with the same name exists in two different packages that you import using the star form, the compiler will remain silent, unless you try to use one of the classes. In that case, you will get a compile-time error and have to explicitly name the class specifying its package.

4. Any place you use a class name, you can use its fully qualified name, which includes its full package hierarchy. When a package is imported, only those items within the package declared as public will be available to non-subclasses in the importing code.

Java visibility of class members

Classes and packages are both means of encapsulating and containing the name space and scope of variables and methods. Packages act as containers for classes and other subordinate packages. Class act as container for data and method code. The class is Java’s smallest unit of abstraction. Because of the interplay between classes and packages, Java addresses five categories of visibility for class members:

1. Visibility within the class

2. Visibility in sub-classes in the same package

3. Visibility in non-sub classes in the same package

4. Visibility in sub-classes in different package

5. Visibility in classes that are neither in the same package nor are sub classes.

A top-level class or interface has only two possible access levels: default and public. When a class is declared public, it is accessible by any other code. If a class has default access, then it can only be accessed by other code within the same package.

The visibility of class members is summarized in the following table:


Note: The member visibility has meaning only if the class is visible. If visibility modifier of the class is default then even public members of the class will be visible only within the package.

Example:

Protection.java

package p1;

public class Protection

{

int n = 1;

private int n_pri = 2;

protected int n_pro = 3;

public int n_pub = 4;

public Protection()

{

System.out.println("Base Constructor");

System.out.println(n);

System.out.println(n_pri);

System.out.println(n_pro);

System.out.println(n_pub);

}

}

To compile: javac –d . Protection.java

Derived.java

package p1;

class Derived extends Protection

{

public Derived()

{

 System.out.println(n);

System.out.println("Derived Constructor");

//System.out.println(n_pri);

System.out.println(n_pro);

System.out.println(n_pub);

  }

}

To compile: javac –d . Derived.java

SamePackage.java

package p1;

class SamePackage

{

public SamePackage()

  {

Protection p = new Protection();

System.out.println("Same Package constructor");

System.out.println(p.n);

//System.out.println(p.n_pri);

System.out.println(p.n_pro);

System.out.println(p.n_pub);

}

}

To compile: javac –d . SamePackage.java

Protection2.java

package p2;

class Protection2 extends p1.Protection

{

Protection2()

{

System.out.println("Protection2 Constructor");

//System.out.println(n);

//System.out.println(n_pri);

System.out.println(n_pro);

System.out.println(n_pub);

}

}

To compile: javac –d . Protection2.java

OtherPackage.java

package p2;

class OtherPackage

{

OtherPackage()

{

p1.Protection p = new p1.Protection();

System.out.println("OtherPackage Constructor");

//System.out.println(p.n);

//System.out.println(p.n_pri);

//System.out.println(p.n_pro);

System.out.println(p.n_pub);

}

}

To Compile: javac –d . OtherPackage.java

Test1.java

package p1;

class Demo

{

public static void main(String args[])

{

Protection ob1 = new Protection();

Derived ob2 = new  Derived();

SamePackage ob3 = new SamePackage();

}

}

To Compile: javac –d . Test1.java

Output:

Base Constructor1234
Base Constructor1234
Derived Constructor134
Base Constructor1234
Same Package Constructor134

Test2.java

package p2;

class Demo

{

public static void main(String args[])

{

Protection2 ob1 = new Protection2();

OtherPackage ob2 = new OtherPackage();

}

}

To Compile: javac –d . Test2.java

Output:

Base Constructor1234
Protection2 Constructor
34
Base Constructor1234
OtherPackage Constructor
4

Java Packages

If no package name is specified in any java file then the class is part of the unnamed package. This requires that every class must have a unique name to avoid collisions. After a while, without some way to manage the namespace, you could run out of convenient descriptive names for individual classes.

You also need some way to be assured that the name you choose for a class will be reasonably unique and not collide with class names chosen by other programmers.

Java provides a mechanism for partitioning the class name space into more manageable chunks. This mechanism is the package.

The package is both a naming and visibility control mechanism.
You can define classes inside a package that are not accessible by code outside that package.
You can also define class members that are only exposed to other members of the same package.
This allows your classes to have intimate knowledge of each other, but not expose that knowledge to the rest of the world.

Defining a package

To create a package, include a package command as the first statement in a Java source file. Any classes declared within that file will belong to the specified package. The package statement defines a name space in which classes are stored. If you omit the package statement, the class names are put into the default package, which has no name and is called un-named package.

This is the general form of package statement:

package pkg_name;

Java uses file system directories to store packages. Remember that case is significant, and directory name must match the package name exactly. More than one file can include the same package statement.

You can create a hierarchy of packages. To do so, simply separate each package name from the one above it by use of a period. The general form of a multi-leveled package statement is shown here:

package pkg_name1 [.pkg_name2] [.pkg_name3];


A package hierarchy must be reflected in the file system of your Java development system.

For example a package declared as:

package java.awt.image;

needs to be stored in java/awt/image, java\awt\image, or java:awt:image on your Unix, Windows, or Macintosh file system, respectively.

A global naming scheme has been proposed to use the reverse Internet domain names to uniquely identify packages.

For example the apache’s domain name is www.apache.org. So to store classes in package tomcat, preferably you should use the package hierarchy:

org.apache.tomcat

which would be unique.

A package hierarchy represents an organization of Java classes and interfaces. It does not represent the source code organization of the classes and interfaces. Each Java source file (also called compilation unit) can contain zero or more definitions of classes and interfaces, but the compiler provides a separate class file containing the Java byte code for each of them. A class or interface can indicate that its java byte code be placed in a particular package, using a package declaration.

At most one package statement can appear in a source file, and it must be the first statement in the unit.

Note that this scheme has two consequences. First, all classes and interfaces in a source file will be placed in the same package. Secondly, several source files can be used to specify the contents of a package.

Finding packages and CLASSPATH

As discussed, packages are mirrored by directories. This raises an important question. How does the Java run-time system know where to look for packages that you create?

There can be two approaches:

First, by default, the Java run-time system uses the current working directory as its starting point. Thus, if your package is in the current directory, or a subdirectory of the current directory, it will be found.

Second, you can specify a directory path or paths by setting the CLASSPATH environment variable. For example, consider the following package specification:

package mypack;

In order for a program to find mypack, one of the two things must be true. Either the program is executed from a directory immediately above mypack, or CLASSPATH must be set to include the path to mypack.

Jar File

If you are developing a complex system or using third party libraries then instead of creating a directory hierarchy for class files you can use .jar files by including them in the CLASSPATH.

The JVM searches for the packages and classes in .jar file as it does searches in the file system.
Instead of .jar file you can also use a .zip file created by any popular software like winzip, winrar etc. Jar files can be created using jar utility that is part of JDK. To include the current directory and all the sub-directories below it in a jar file give the following command:

jar -cf myjar.jar *

here, c stands for creating a new .jar file.

         f stands for name of the .jar file.

The above command will create myjar.jar file in the current folder.

Example:

package mypack;

public class MyProg

{ public static void main(String args[])

{ System.out.println("Yes, Its working!");

}

}

To compile the following program give following command:

C:\totest>javac -d . MyProg.java

Here -d is used to create a directory ‘mypack’ in the current folder and put the class file in this folder automatically. When we compile the program, ‘mypack’ directory is created in the current folder (which is assumed to be c:\totest).

We can run above program in following different ways:

1. Running from the current directory: 

Give the following command from the directory where the package directory is created i.e from folder c:\totest.

java mypack.MyProg

This is because, MyProg file is part of package mypack.

Output:

Yes, Its working!

2. Running using classpath:

Give the following command at the command prompt:

SET CLASSPATH = %CLASSPATH%;C:\totest;

Then give the following command from any directory/folder:

java mypack.MyProg

3. Running by specifying classpath as parameter

Give the following command:

 java –classpath c:\totest mypack.MyProg

4. Running using jar file: Go to C:\totest folder and give the following command:

 jar –cf myjar.jar mypack (or jar -cf myjar.jar mypack)

and then give the following command:

java -classpath c:\totest\myjar.jar mypack.MyProg

After creating the .jar file, you can also set the classpath as follows:

set classpath=%classpath%;c:\totest\myjar.jar

Note: you can use –d option to copy the class file in any desired folder. For example, use the following command to create folder ‘mypack’ in C:\myclasses:

javac –d C:\myclasses MyProg.java

This will create a folder mypack below myclassses, if not already present and put the MyProg.class file in it.

Java Abstract Classes

There are situations in which you will want to define a super class that declares the structure of a given abstraction without providing a complete implementation of every method. That is, sometimes you will want to create a super class that only defines a generalized form that will be shared by all of its subclasses, leaving it to each sub class to fill in the details. Such a class determines the nature of the methods that the sub classes must implement. One way this situation can occur is when a super class is unable to create a meaningful implementation for a method.

This is the case with the class Shape used in the preceding example. The definition of area() is simply placeholder. It will not compute and display the area of any type of object. When you create your own class libraries, it is not uncommon for a method to have no meaningful definition in the context of its super-class.

You can handle this situation in two ways: 

One way, as shown in the previous example, is to simply have it report a warning message. While this approach can be useful in certain situations- such as debugging. It is not usually appropriate. You may have methods, which must be overridden by the sub class in order for the sub class to have any meaning.

Consider the class triangle. It has no meaning if area() is not defined. In this case, you want some way to ensure that a sub class does, indeed, override all necessary methods.

Java’s solution to this problem is the abstract method. You can require that certain methods be overridden by subclasses by specifying the abstract type modifier. These methods are sometimes referred to as subclass responsibility because they have no implementation specified in the super class. Thus a sub class must override them – it can not simply use the version defined in the super class. To declare an abstract method, use this general form:

abstract return_type name(parameter-list);

As you can see, no method body is present. Any class that contains one or more abstract methods must also be declared abstract. To declare a class abstract, you simply use the abstract keyword in front of the class keyword at the beginning of the declaration.

There can be no object of an abstract class. That is, an abstract class can not be directly instantiated with the new operator. Such objects would be useless, because an abstract class is not fully defined. Also you cannot declare abstract constructors or abstract static methods. Any subclass of an abstract class must either implement all of the abstract methods in super class, or be itself declared abstract. Here, is a simple example of a class with an abstract method, followed by a class which implements that method.

Example:

1 abstract class Shape //abstract class

2 { double puCost = 100;

3 abstract double area(); //abstract method.

4 double calCost()

5 {  return puCost * area();

6 }

7 }

1 class Triangle extends Shape

2 {

3 double s1,s2,s3;

4 Triangle(double a, double b, double c)

5 {

6   s1 = a; s2 = b; s3 = c;

7 }

8 double area()

9 {

10 double s = (s1+s2+s3)/2;

11 return Math.sqrt(s*(s-s1)*(s-s2)*(s-s3));

12 }

13 }

1 class Rectangle extends Shape

2 { double s1,s2;

3 Rectangle(double a, double b)

4 {

5  s1 = a; s2 = b;

6 }

7 double area()

8 {

9 return s1 * s2;

10 }

11 }

1 class Square extends Shape

2 {

3 double s;

4 Square(double a)

5 {

6   s = a;

7 }

8 double area()

9 {

10 return s * s;

11 }

12 }

1 class ShapeTest1

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

3     { //Shape s = new Shape();

4   Shape s1 = new Triangle(3,4,5);

5   Shape s2 = new Rectangle(3,4);

6   Shape s3 = new Square(3);

7   //System.out.println(s.area());

8   System.out.println(s1.area());

9   System.out.println(s2.area());

10   System.out.println(s3.area());

11   //System.out.println(s.calCost());

12   System.out.println(s1.calCost());

13   System.out.println(s2.calCost());

14   System.out.println(s3.calCost());

15 }

16 }

Output:

6.0
12.0
9.0
600.0
1200.0
900

Java Method Overriding and Dynamic Binding

Method Overriding

In a class hierarchy, when a instance method in a subclass has the same signature as an instance method (non-private) in its super class, then the method in the sub-class is said to override the method in the super-class. When an overridden method is called from within a sub-class, it will always refer to the version of that method defined by the sub-class. The version of the method defined by the super-class will be hidden.

Please not that the concept of overriding is applicable only for instance methods. Static methods cannot be overridden. It is not possible to override even an instance method if its visibility is private.

While overriding a method, we cannot decrease the visibility. The visibility of the method in the child class should be same or higher. The visibility of a method overriding a public method can be public only. The visibility of a method overriding a protected method can be protected or public. Similarly the visibility of a method overriding a method with the package visibility can be package, protected or public.

Dynamic Method Binding (Dynamic Method Dispatch or Run-time Binding) 

Method overriding forms the basis for one of Java’s most powerful concepts. Dynamic method dispatch is the mechanism by which a call to an overridden instance method is resolved at run time, rather than compile time.

Dynamic method dispatch is important because this is how Java implements run-time polymorphism.
A super-class reference variable can refer to a sub-class object. Java uses this fact to resolve calls to overridden methods at run time. When an overridden method is called through a super-class 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 reference) that determines which version of an overridden method will be executed.

Why Overridden Methods?

Overridden methods allow Java to support run-time polymorphism. Polymorphism is essential for OOP for one reason: It allows a general class to specify methods that will be common to all of its derivatives, while allowing sub classes to define the specific implementation of some or all of these methods.

By combining inheritance with overridden methods, a super-class can define the general form of method that will be used by all of its sub classes.

The ability of existing code libraries to call methods on instances of new classes without recompiling while maintaining a clean abstract interface is a profoundly powerful tool.

Example: The following example illustrates the concept of method overriding and dynamic binding.

1 class A

2 { int i,j;

3 A(int a, int b)

4 {

5 i = a; j = b;

6 }

7 void show()

8 {

9 System.out.println(i);

10 System.out.println(j);

11 }

12 }

1 class B extends A

2 { int k = 5;

3 B(int a, int b, int c)

4 {

5 super(a,b);

6 k = c;

7 }

8 void show()

9 { System.out.println(k);

10 }

11 }

1 class OverridingDemo1

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

3 { B b = new B(1,2,3); b.show();

4     A a = b;

5     a.show();

6   }

7 }

Output:
3
3

Example: The following example illustrates that the overridden method of the super class can be invoked through super keyword.

1 class A

2 { int i,j;

3 A(int a, int b)

4 { i = a; j = b;

5 }

6 void show()

7 { System.out.println(i);

8 System.out.println(j);

9 }

10 }

1 class B extends A

2 { int k = 5;

3 B(int a, int b, int c)

4 {

5 super(a,b);

6 k = c;

7 }

8 void show()

9 { super.show(); //this call’s the A’s show()

10 System.out.println(k);

11 }

12 }

1 class OverridingDemo2

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

3 { B b = new B(1,2,3); b.show();

4 A a = b;

5 a.show();

6 }

7 }

Output:

1
2
3
1
2
3

Here, super.show() calls the super class version of show().

Method overriding occurs only when the signature of the two methods are identical. If not, then the two methods are simply overloaded.

Example: The following example illustrates that the show() method in the sub-class does not override the show() method in the super-class as their signatures are different. The show() method is just overloaded.

1 class A

2 { int i,j;

3 A(int a, int b)

4 { i = a; j = b;

5 }

6 void show()

7 { System.out.println(i);

8 System.out.println(j);

9 }

10 }

1 class B extends A

2 { int k = 5;

3 B(int a, int b, int c)

4 { super(a,b);

5 k = c;

6 }

7 void show(String msg)

8 { System.out.println(msg + k);

9 }

10 }

1 class OverridingDemo3

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

3   { B b = new B(1,2,3); b.show("Value of k: "); b.show();

4     }

5 }

Output:

Value of k:

3
1
2

Example:

The stack class defined earlier can hold only ten elements in the stack. We want a dynamic stack, which can hold any number of elements in the stack. We can rewrite the push() method of the existing class Stack or ExtStack. But the better alternative is to define another class by extending the Stack or ExtStack class and overriding the push() method. This will not affect any existing code, which is using Stack or ExtStack class. The push() method in the derived class will have exactly same signature as the push() method in the base-class but the body of the method will be different so as to implement the dynamic stack.

1 class DynamicStack extends ExtStack 

2 { public void push(int x)

3 { int b[];

4 if(top == a.length-1)

5 { b = new int[2*a.length];

6 for(int i = 0; i < a.length; i++)

7 b[i] = a[i];

8 a = b; //a now points to a new array of double size

9 }

10 top = top + 1;

11 a[top] = x;

12 }

13 }

The following program makes use of the overridden method push(). It is now possible to push any number of elements till the JVM has free memory.

1 class StackDemo2

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

3 { DynamicStack s = new DynamicStack();

4 for(int i = 0; i < 10; i++)

5 { s.push(100+i);

6 }

7 for(int i = 0; i < 10; i++)

8 { s.push(100+i);

9 }

10 for(int i = 0; i < 10; i++)

11 { s.push(100+i);

12 }

13 s.display();

14 }

15 }

Example: It is possible to access the overridden method through base class reference. This can be achieved by creating object of sub-class and assigning its reference to a reference variable of base-class.

The following example demonstrates this concept. But a base-class reference can be used to access only features defined in the base-class even if it points to an object of the sub-class. If a reference of base-class actually points to an object of sub-class, you can typecast it to get sub-class reference and then use it to access the features, which are specific to the sub-class.

Following example demonstrates these concepts.

1 class StackDemo3

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

3 { Stack s = new DynamicStack();

4 for(int i = 0; i < 10; i++)

5 { s.push(100+i);

6 }

7 for(int i = 0; i < 10; i++)

8 { s.push(100+i);

9 }

10 //boolean b = s.isStackFull();

11 //s.display();

12 DynamicStack ds = (DynamicStack) s;

13 boolean b = ds.isStackFull();

14 ds.display();

15 }

16 }

We have created an object of type DynamicStack and assigned the reference in a reference variable of type Stack, which is valid as it is up-casting and takes place implicitly as discussed above. But we can access only the features of the base-class through the reference of type Stack.

Hence the call to methods s.isStackFull() and s.display() are commented as they are not valid. But observe that call s.push() actually calls push() method of the sub-class as it is over-ridden. This is why we are able to insert more than 10 elements in the stack.

Finally, in this program reference of type Stack (s) is typecasted back to reference of type DynamicStack (ds). This is down-casting so explicit typecast is needed. Typecasting will be valid only if the referred object is of type DynamicStack. We can now call ds.isStackFull() and ds.display() methods.

Example: The following example illustrates that it is possible to write generic code using inheritance, method over-riding and dynamic binding features.

1 class Shape

2 { double puCost = 100;

3 double area()

4 { System.out.println("Area is not defined");

5 return 0;

6 }

7 double calCost()

8 { return puCost * area();

9 }

10 }

1 class Triangle extends Shape

2 { double s1,s2,s3;

3 Triangle(double a, double b, double c)

4 {  s1 = a; s2 = b; s3 = c;

5 }

6 double area()

7 { double s = (s1+s2+s3)/2;

8 return Math.sqrt(s*(s-s1)*(s-s2)*(s-s3));

9 }

10 }

1 class Rectangle extends Shape

2 { double s1,s2;

3 Rectangle(double a, double b)

4 {  s1 = a; s2 = b;

5 }

6 double area()

7 { return s1 * s2;

8 }

9 }

1 class Square extends Shape

2 { double s;

3 Square(double a)

4 {  s = a;

5 }

6 double area()

7 { return s * s;

8 }

9 }

1 class ShapeTest

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

3 { Shape s = new Shape();

4   Shape s1 = new Triangle(3,4,5);

5  Shape s2 = new Rectangle(3,4);

6 Shape s3 = new Square(3);

7 System.out.println(s.area());

8   System.out.println(s1.area());

9   System.out.println(s2.area());

10   System.out.println(s3.area());

11   System.out.println(s.calCost());

12   System.out.println(s1.calCost());

13   System.out.println(s2.calCost());

14   System.out.println(s3.calCost());

15 }

16 }

Output:

Area is not defined
0.0
6.0
12.0
9.0
Area is not defined
0.0
600.0
1200.0
900.0

Note: If an object is derived from Shape, then its area can be obtained by calling area() method.
The interface to this operation is the same no matter what type of Shape is being used.

Java Multilevel Hierarchy example

Example: The following example demonstrates a multi-level hierarchy.

1 class Box

2 { private double width, height, depth; //data hiding

3 double volume()

4 { double vol = width * height * depth;

5 return vol;

6 }

7 Box(double w, double h, double d)

8 { width = w; height = h; depth = d;

9 }

10 Box()

11 { width = -1; height = -1; depth = -1;

12 }

13 Box(double len)

14 { width = height = depth = len;

15 }

16 Box(Box ob)

17 {  width = ob.width; height = ob.height; depth = ob.depth;

18 }

19 }

1 class BoxWeight extends Box

2 { double weight;

3 BoxWeight(BoxWeight ob)

4 { super(ob);

5 weight = ob.weight;

6 }

7 BoxWeight(double w, double h, double d, double m)

8 { super(w,h,d); weight = m;

9 }

10 BoxWeight()

11 { super(); weight = -1;

12 }

13 BoxWeight(double len, double m)

14 { super(len); weight = m;

15 }

16 }

1 class Shipment extends BoxWeight

2 {

3 double cost;

4 Shipment(Shipment ob)

5 { super(ob); cost = ob.cost;

6 }

7 Shipment(double w, double h, double d, double m, double c)

8 { super(w,h,d,m); cost = c;

9 }

10 Shipment()

11 { super(); cost  = -1;

12 }

13 Shipment(double len, double m, double c)

14 { super(len,m); cost = c;

15 }

16 }

1 class ShipmentDemo

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

3    { Shipment s = new Shipment(10,20,15,34.3,1000);

4 double vol = s.volume();

5 System.out.println(vol);

6 System.out.println(s.weight);

7 System.out.println(s.cost);

8 }

9 }

Output:
3000.0
34.3
1000.0

This example illustrates one important point: super() always refers to the constructor in the immediate super class. The super() in shipment calls the constructor in BoxWeight. The super() in BoxWeight calls the constructor in Box.

In a class hierarchy if a super class constructor requires parameters, then all subclasses must pass those parameters “up the line”. This is true whether or not a subclass needs parameters of its
own.

1. Order in which Constructors are called

When a class hierarchy is created, in what order are the constructors for the classes that make up the hierarchy called? The answer is that in a class hierarchy, constructors are called in order of derivation, from super class to subclass.

Further, since super() must be the first statement executed in a subclass’s constructor; this order is the same whether or not super() is used. If super() is not used, then the default or parameter less constructor of each super class will be executed.

Example: The following example illustrates the order in which constructors are called when child class object is created in case of a multi-level hierarchy.

1 class A

2 { A()

3 { System.out.println("A's Constructor");

4 }

5 }

1 class B extends A

2 { B()

3 { System.out.println("B's Constructor");

4 }

5 }

1 class C extends B

2 { C()

3 { System.out.println("C's Constructor");

4 }

5 }

1 class ConstOrderDemo

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

3    { C c = new C();

4 }

5 }

Output:

A's Constructor
B's Constructor
C's Constructor

As you can see constructors are called in order of derivation. It makes sense that constructors are executed in order of derivation. Because a super class has no knowledge of any sub class, any initialization it needs to perform is separate and possibly pre-requisite to any initialization performed by the sub class. Therefore it must be executed first.


Saturday, 30 May 2015

Java Member Hiding

If a sub-class member has the same name (and same signature in case of methods) as that of a super-class member then it hides the super-class member.

Although both the members might be available in the sub-class but using member name we can only access sub-class member as it hides the member of the same name in the super-class.

There is a way of accessing a hidden member, which is discussed in the next section. 


Java keyword super

In the previous example, class BoxWeight derived from Box was not implemented as efficiently or as robustfully as it could have been.

For example, the constructor for BoxWeight explicitly initializes the width, height, and depth fields of Box(). Not only does this duplicate code of its super class, which is in-efficient, but it implies that a subclass must be granted access to these members.

However, there will be times when you will want to create a super class that keeps the details of its implementation to itself (that is, it keeps its data members private). In this case, there would be no way for a subclass to directly access or initialize these variables on its own.

Since encapsulation is a primary attribute of OOP, it is not surprising that Java provides a as solution to this problem.

Whenever a subclass needs to refer to its immediate super class, it can do so by use of keyword super.

The super has two general uses:


  • Calling super class’s constructor
  • Accessing a member of the super-class that has been hidden by a member of a sub-class.


1. Using super to call super class constructors

A subclass can call a constructor method defined by its super class by use of the following form of super:

super(parameter-list);

Here, parameter-list specifies any parameters needed by the constructor in the super class. In fact super() must always be the first statement executed inside a subclass’s constructor.

To see how super() is used, consider the improved version of the BoxWeight() class in the following example.

Example:

1 class Box

2 { private double width, height, depth; //data hiding

3 double volume()

4 { double vol = width * height * depth;

5 return vol;

6 }

7 Box(double w, double h, double d)

8 { width = w; height = h; depth = d;

9 }

10 Box()

11 { width = -1; height = -1; depth = -1;

12 }

13 Box(double len)

14 { width = height = depth = len;

15 }

16 Box(Box ob)

17 { width = ob.width; height = ob.height; depth = ob.depth;

18 }

19 }

1 class BoxWeight extends Box

2 { double weight;

3 BoxWeight(double w, double h, double d, double m)

4 { super(w,h,d);

5 weight = m;

6 }

7 }

1 class BoxWeightDemo1

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

3 { BoxWeight bw1 = new BoxWeight(10,20,15,34.3);

4 double vol;

5 vol = bw1.volume();

6 System.out.println(vol);

7 System.out.println(bw1.weight);

8 Box b1 = bw1;

9 vol = b1.volume();

10 System.out.println(vol);

11 //System.out.println(b1.weight); //will not compile

12 //BoxWeight bw2 = b1; //will not compile

13 BoxWeight bw2 = (BoxWeight) b1;

14 vol = bw2.volume();

15 System.out.println(vol);

16 System.out.println(bw2.weight);

17 Box b2 = new Box(5);

18 BoxWeight bw3 = (BoxWeight) b2;

19 System.out.println(bw3.weight);

20

21 }

22 }

Output:

3000.0
34.3
3000.0
3000.0
34.3

Exception in thread "main" java.lang.ClassCastException: Box

        at BoxWeightDemo1.main(BoxWeightDemo1.java:18)

Here, BoxWeight() constructor calls super() with the parameters w, h, d. This causes the Box(double w, double h, double d)  constructor to be called, which initializes width, height and depth using these values. BoxWeight no longer initialize these values itself. It only needs to initialize the value unique to it i.e. weight. This leaves Box free to make these values private if desired.

In the preceding example, super() was called with three arguments. Since constructors can be overloaded, super() can use any form defined by the super class. The constructor executed will be one that matches the arguments.

The line number 18 in the BoxWeightDemo1.java class will result in run-time exception as we are trying to down-cast a super class reference which is actually pointing to a super-class object and hence is not a valid down-cast.

Example: The following example illustrates how super can be used to invoke overloaded constructors of the super class.

1 class Box

2 { private double width, height, depth; //data hiding

3 double volume()

4 { double vol = width * height * depth;

5 return vol;

6 }

7 Box(double w, double h, double d)

8 { width = w; height = h; depth = d;

9 }

10 Box()

11 { width = -1; height = -1; depth = -1;

12 }

13 Box(double len)

14 { width = height = depth = len;

15 }

16 Box(Box ob)

17 { width=ob.width; height=ob.height; depth=ob.depth;

18 }

19 }

1 class BoxWeight extends Box

2 { double weight;

3 BoxWeight(BoxWeight ob)

4 { super(ob);

5 weight = ob.weight;

6 }

7 BoxWeight(double w, double h, double d, double m)

8 { super(w,h,d);

9 weight = m;

10 }

11 BoxWeight()

12 { super(); weight = -1;

13 }

14 BoxWeight(double len, double m)

15 { super(len); weight = m;

16 }

17 }

1 class BoxWeightDemo2

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

3  { BoxWeight bw1 = new BoxWeight(10,20,15,34.3);

4 BoxWeight bw2 = new BoxWeight(2,3,4,14.2);

5 BoxWeight bw3 = new BoxWeight();

6 BoxWeight bw4 = new BoxWeight(3,5);

7 BoxWeight bw5 = new BoxWeight(bw1);

8 double vol;

9 vol = bw1.volume();

10 System.out.println(vol);

11 System.out.println(bw1.weight);

12 vol = bw2.volume();

13 System.out.println(vol);

14 System.out.println(bw2.weight);

15 vol = bw3.volume();

16 System.out.println(vol);

17 System.out.println(bw3.weight);

18 vol = bw4.volume();

19 System.out.println(vol);

20 System.out.println(bw4.weight);

21 vol = bw5.volume();

22 System.out.println(vol);

23 System.out.println(bw5.weight);

24 }

25 }

Output:

3000.0
34.3
24.0
14.2
-1.0
-1.0
27.0
5.0
3000.0
34.3

Notice that Box(Box ob) is called using super() by passing a parameter of type BoxWeight, not of Box.

As mentioned earlier, super class variable can be used to reference any object derived from that class. Thus, we are able to pass a BoxWeight object to the Box constructor. Of course, Box only has knowledge of its own members.

When a subclass calls super(), it is calling the constructor of its immediate super class. Thus, super() always refers to the super class immediately above the calling class. This is true even in a multi-level hierarchy.

Also, super() must always be the first statement executed inside a sub-class constructor. If a sub-class constructor does not call the super-class’s constructor explicitly then the compiler implicitly puts the call to super-class’s no-argument constructor.

2. Using super to access hidden member of the super class.

The keyword super can be used to access the hidden members of the super as follows:

super.member;

Here, member can be either a method or a data member.

Example: The following example illustrates how to access hidden members of the super- class from sub-class

1 class A

2 { protected int x = 10;

3 public void m1()

4 { System.out.println("m1() of A");

5 }

6 }

1 class B extends A

2 { int x = 5;

3 public void m1()

4 { System.out.println("m1() of B");

5 }

6 public void m2()

7 { System.out.println(super.x);

8 System.out.println(x);

9 m1();

10 super.m1();

11 }

12 public static void main(String args[])

13 { B b = new B(); b.m2();

14 }

15 }

Output:

10
5
m1() of B
m1() of A

Example: The following example illustrates use of super in a multi-level hierarchy.

1 class A

2 { int x = 1;

3 }

1 class B extends A

2 { int y = 2;

3 }

1 class C extends B

2 { int x = 3;

3 void show()

4 { System.out.println(x);

5 System.out.println(y);

6 System.out.println(super.x);

7 }

8 }

1 class Super

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

3 { C c = new C();

4 c.show();

5   }

6 }

Output:

3
2
1

Example: The following example also illustrates use of super in a multi-level hierarchy where

all the classes in the hierarchy have the members with the same name.

1 class A

2 { int x = 1;

3 }

1 class B extends A

2 { int y = 2;

3 int x = 4;

4 int getSuperX()

5 {

6 return super.x;

7 }

8 }

1 class C extends B

2 { int x = 3;

3 void show()

4 { System.out.println(x);

5 System.out.println(y);

6 System.out.println(getSuperX());

7 System.out.println(super.x);

8 }

9 }

1 class Super2

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

3 { C c = new C();

4 c.show();

5  }

6 }

Output:

3
2
1
4

Java Down-Casting and Up-Casting

A reference to a sub-class object can be stored into a reference type variable of base-class/super-class without any explicit conversion, this is called up-casting. This is like widening conversion used in case of primitive types and takes place implicitly.

A reference to a base-class/super-class object can not be stored into a reference type variable of sub-class without explicit conversion, this is called down-casting. This is like narrowing conversion used in case of primitive types and needs explicit type-casting. The down-casting is valid only if the super class reference points to the sub-class object before down-casting.

Super class variable can refer to a sub-class object

Example: The following example illustrates that a super-class variable can refer to a sub-class object.

Reference variable of a super class can be assigned a reference to any subclass derived from that super class. It is important to understand that it is the type of the reference variable not the type of the object that it refers to that determine what can be accessed.

That is, when a reference to a subclass object is assigned to a super class reference variable, you will have access only to those parts of the object defined by the super class. This is why Box reference cannot access weight even when it refers to a BoxWeight object. If you think about it, this makes sense, because the super class has no knowledge of what a subclass adds to it. This is why the last line of following code is commented out. It is not possible for a Box reference to access the weight field, because it does not define one.

1 class Box

2 { double width, height, depth;

3 double volume()

4 { double vol = width * height * depth;

5 return vol;

6 }

7 Box(double w, double h, double d)

8 { width = w;

9 height = h;

10 depth = d;

11 }

12 Box()

13 { width = -1;

14 height = -1;

15 depth = -1;

16 }

17 Box(double len)

18 { width = height = depth = len;

19 }

20 Box(Box ob)

21 { width = ob.width;

22 height = ob.height;

23 depth = ob.depth;

24 }

25 }

1 class BoxWeight extends Box

2 {

3 double weight;

4 BoxWeight(double w, double h, double d, double m)

5 { width = w;

6 height = h;

7 depth = d;

8 weight = m;

9 }

10 }

1 class BoxWeightDemo

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

3   { BoxWeight bw1 = new BoxWeight(10,20,15,34.3);

4    BoxWeight bw2 = new BoxWeight(2,3,4,51);

5 double vol;

6 vol = bw1.volume();

7 System.out.println(vol);

8 System.out.println(bw1.weight);

9 vol = bw2.volume();

10 System.out.println(vol);

11 System.out.println(bw2.weight);

12 Box b1 = new Box();

13 vol = b1.volume();

14 System.out.println(vol);

15 b1 = bw1;

16 vol = b1.volume();

17 System.out.println(vol);

18 //System.out.println(b1.weight); will not compile

19 }

20 }

Output:

3000.0
34.3
24.0
51.0
-1.0
3000.0

Here BoxWeight inherits all of the characteristics of Box and adds the weight component. A major advantage of inheritance is that once you have created a super class that defines the
attributes common to a set of objects, it can be used to create any number of more specific
subclasses. Each subclass can precisely tailor its own classification.

Remember once you have created a super class that defines the general aspects of an object, that super class can be inherited to form specialized classes. Each subclass simply adds its own, unique attributes.

Java Object Class

Even if you write a simple class (i.e. it is not extending any base-class), it implicitly extends built-in Object class. So the Object class is at the root of all the hierarchies in Java. Thus the features of this class will be available in all the classes.

Example: The following example illustrates the basic concepts of inheritance.

class A

{ int i,j; // or protected int i,j; or public int i,j;

void showij()

{ System.out.println(i); System.out.println(j);

}

}

class B extends A

{ int k;

void showk()

{ System.out.println(k);

}

void sum()

{ System.out.println(i+j+k);

}

}

class InheritanceDemo

{ public static void main(String args[])

{ A a = new A();

B b = new B();

a.i = 10; a.j = 20;

a.showij();

b.i = 7; b.j = 8; b.k = 9;

b.showij(); b.showk();

a.showij();

b.sum();

}

}

Output:

10
20
7
8
9
10
20
24

Example: The following example illustrates that although private members are not inherited but
they can be accessed through methods.

1 class A

2 { private int i,j;

3 void showij()

4 { System.out.println(i); System.out.println(j);

5 }

6 void setI(int x)

7 { i = x;

8 }

9 void setJ(int x)

10 { j = x;

11 }

12 int getI()

13 { return i;

14 }

15 int getJ()

16 { return j;

17 }

18 }

19 class B extends A

20 { int k;

21 void showk()

22 { System.out.println(k);

23 }

24 void sum()

25 { System.out.println(getI()+getJ()+k);

26 }

27 }

28 class InheritanceDemo1

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

30 { A a = new A();

31 B b = new B();

32 a.setI(10); a.setJ(20);

33 a.showij();

34 b.setI(7); b.setJ(8); b.k = 9;

35 b.showij(); b.showk();

36 a.showij();

37 b.sum();

38 }

39 }

Output:

10
20
7
8
9
10
20
24

Example: The following example defines class Stack with two operations push() and pop(). We
will then extend this class to provide some more features (like adding operations display(), isStackEmpty() and isStackFull().

1 class Stack

2 {

3 int top = -1;

4 int a[] = new int[10];

5 void push(int x)

6 {

7 if(top == 9)

8 { System.out.println("Stack Full");

9 return;

10 }

11 top = top + 1;

12 a[top] = x;

13 }

14 int pop()

15 {

16 if(top ==  -1)

17 { System.out.println("Stack Empty");

18 return -1; //assuming that –1 is not a valid data

19 }

20 int x = a[top];

21 top = top - 1;

22 return x;

23 }

24 }

The following class makes use of the Stack class defined above. In the main method, we have created an instance of the class Stack, pushed 10 elements on the stack and then finally we are removing the elements from the stack using pop() and displaying them. Accepting input from the user to decide what operation is to be performed can further extend the program.

1 class StackDemo

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

3 { Stack s = new Stack();

4 for(int i = 0; i < 10; i++)

5 { s.push(100+i);

6 }

7 int x;

8 for(int i = 0; i < 10; i++)

9 {

10 x = s.pop();

11 System.out.println(x);

12 }

13 }

14 }

The following class adds new features to the class Stack by extending it. The methods push() and pop() and instance variables top and a[] are available in the extended class because of inheritance.

1 class ExtStack extends Stack

2 { void display()

3 { for(int i = top; i >= 0; i--)

4 { System.out.println(a[i]);

5 }

6 }

7 boolean isStackEmpty()

8 { if(top == -1)

9 return(true);

10 else

11 return(false);

12 }

13 boolean isStackFull()

14 { if(top == 9)

15 return(true);

16 else

17 return(false);

18 }

19 }

The following class makes use of the ExtStack class, which is derived by extending the class Stack. You can see that it uses the features of the base-class as well as derived class.

1 class StackDemo1

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

3 { ExtStack s = new ExtStack();

4 int i=0;

5 for(i = 0; i < 10; i++)

6 { s.push(100+i);

7 }

8 s.push(i); //will lead to stack overflow

9 if(s.isStackFull())

10 System.out.println("Stack is full");

11 s.display(); //Stack will be displayed without deleting

12 int x; //elements are popped() and  displayed

13 for(i = 0; i < 10; i++)

14 { x = s.pop();  System.out.println(x);

15 }

16 s.pop(); //will lead to stack underflow

17 if(s.isStackEmpty())

18 System.out.println("Stack is empty");

19 }

20 }

Java Extending a Class

To inherit a class, you simply incorporate the definition of one class into another by using the extends keyword.

Java supports only Single-Inheritance in the case of classes to avoid ambiguity and complexity although it supports Multiple-Inheritance in the case of interfaces.

The general form for deriving a sub-class from an existing class is as follows:

class <sub-class> extends <base-class>
{

<class-definition>

}

The derived class will have all the features of base-class in addition to the new features defined in the extended class. Java does not support multiple-inheritance so sub-class can extend only one base-class. It is possible that two different classes can extend the same base-class. A sub-class can also be further extended and the hierarchy can go to any depth. Thus by extending a base-class we can form hierarchy of classes all derived from the same base class.

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 Method Returning Boolean Value

The Java supports primitive data type boolean, which can be used as return type.

Example: The following program uses a method that returns boolean value true or false depending on whether a given positive integer number greater than 2 is prime or not.

1 class CheckPrime

2 { static boolean checkPrime(int number)

3 { int root = (int) Math.sqrt(number);

4 for(int i  = 2; i <= root; i++)

5 { if( number % i = = 0)

6 return false; 

7 }

8 return true;

9 } 

10 public static void main(String a[])

11 { int n = Integer.parseInt(a[0]);

12 boolean prime = checkPrime(n);

13 if(prime)

14 System.out.println("The number " + n + " is prime");

15 else

16 System.out.println("The number " + n + " is not prime");

17 }

18 }

13. Examples

Example: The following example shows the static implementation (using array) of stack.

1 class Stack

2 { private int top = -1;

3 private int a[] = new int[10];

4 void push(int x)

5 { if(top == 9)

6 { System.out.println("Stack Full");

7 return;

8 }

9 top = top + 1;

10 a[top] = x;

11 }

12 int pop()

13 { if(top ==  -1)

14 { System.out.println("Stack Empty");

15 return -1; //assuming that -1 is not a valid data

16 }

17 int x = a[top]; top = top - 1;

18 return x;

19 }

20 }

class StackDemo

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

2 { Stack s1 = new Stack();

3 Stack s2 = new Stack();

4 for(int i = 0; i < 10; i++)

5 { s1.push(i);

6 }

7 for(int i = 10; i < 20; i++)

8 { s2.push(i);

9 }

10 int x;

11 for(int i = 0; i < 10; i++)

12 { x = s1.pop();

13 System.out.print(x + " ");

14 }

15 System.out.println();

16 for(int i = 0; i < 10; i++)

17 { x = s2.pop();

18 System.out.print(x + " ");

19 }

20 }

Output:

9 8 7 6 5 4 3 2 1 0

19 18 17 16 15 14 13 12 11 10

Example: The following example demonstrates that only one copy per class is created in case of static members. Thus the implementation is not correct if data member top and a[] are declared to be static as in that case all the objects of Stack class will share the same memory.

1 class Stack

2 { static int top = -1;

3 static int a[] = new int[10];

4 static void push(int x)

5 { if(top == 9)

6 { System.out.println("Stack Full"); 

7 return;

8 }

9 top = top + 1;

10 a[top] = x;

11 }

12 static int pop()

13 { if(top ==  -1)

14 { System.out.println("Stack Empty");

15 return -1; //assuming that -1 is not a valid data

16 }

17 int x = a[top];

18 top = top - 1;

19 return x;

20 }

21 }

1 class StackDemo

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

3 { Stack s1 = new Stack();

4 Stack s2 = new Stack();

5 for(int i = 0; i < 10; i++)

6 { s1.push(i);

7 }

8 for(int i = 10; i < 20; i++)

9 { s2.push(i);

10 }

11 int x;

12 for(int i = 0; i < 10; i++)

13 { x = s1.pop();

14 System.out.print(x + " ");

15 }

16 System.out.println();

17 for(int i = 0; i < 10; i++)

18 { x = s2.pop();

19 System.out.print(x + " ");

20 }

21 }

22 }

Output:

Stack Full

Stack Full

Stack Full

Stack Full

Stack Full

Stack Full

Stack Full

Stack Full

Stack Full

Stack Full

9 8 7 6 5 4 3 2 1 0

Stack Empty

-1 Stack Empty

-1 Stack Empty

-1 Stack Empty

-1 Stack Empty

-1 Stack Empty

-1 Stack Empty

-1 Stack Empty

-1 Stack Empty

-1 Stack Empty

-1

Example: The following example shows the dynamic implementation (using linked list) of stack.

1 class Node

2 { Node nextNode;

3 int x;

4 }

1 class Stack

2 { Node top;

3 void push(int item)

4 { Node temp;

5 if(top == null)

6 { top = new Node();

7 top.x = item; top.nextNode = null;

8 }

9 else

10 { temp = new Node();

11 temp.x = item;

12 temp.nextNode = top;

13 top = temp;

14 }

15 }

16 int pop()

17 { if(top == null)

18 { System.out.println("Stack is empty");

19 return(-1);

20 }

21 else

22 { int x = top.x; top = top.nextNode;

23 return x;

24 }

25 }

26 } 

1 class StackTest

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

3 { Stack st = new Stack();

4 st.pop();

5 for(int i = 0; i < 5; i++)

6 st.push(i); 

7 for(int i = 0; i <= 5; i++)

8 System.out.println(st.pop()); 

9 }

10 }

Output:

Stack is empty

4

3

2

1

0

Stack is empty

-1

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 Constructors

It is very common requirement to initialize an object immediately after creation. We can define instance methods for this purpose but they have to be invoked explicitly. Java has a solution for this requirement. Java allows objects to initialize themselves when they are created using constructors.

The syntax of the constructors is very similar to that of instance methods. They have the same name as the class and do not have any return type. This is because the implicit return type of a class’s constructor is the class itself. Constructors can be overloaded just like methods.

When operator new is used to create an instance/object of a class, JVM allocates memory for the object, then initializes the instance variables to their default initial values, and then calls the appropriate constructor to initialize the instance variables.

We have not explicitly used constructors so far. But every class has a default constructor that does not take any argument and its body does not have any statements. The compiler generates the default constructor automatically. The compilers stops generating default constructor as soon as you add your own constructor.

Note: The name constructor is a bit confusing. It appears as if the purpose of the constructor is to create an object/instance. The object is created and instance variables and static variables are initialized to their default initial values before constructor is called. So the purpose of the constructor is to initialize the instance variables after the object has been created.

1. Default Constructor

Example: The following program does not define any constructor so it uses the default constructor, which does not take any parameters.

1 class Box

2 { float width;

3 float height;

4 float depth;

5 public static void main(String args[])

6 { Box b = new Box();

7 float volume = b.width * b.height * b.depth;

8 System.out.println("Volume = " + volume);

9 }

10 }

The compiler would automatically generate the following default constructor while compiling the above program:

Box()

{

}

The output of the above program will be 0 (Zero) as constructor is not doing any initialization and default initial value of float type instance variables is 0 (Zero).

2. No Argument Constructor

You can replace the default constructor with your own no argument constructor. This will allow you to initialize the instance variables to any value.

Example: The following program defines a no argument constructor, which is called immediately after creation of object.

1 class Box

2 { private double width, height, depth; //data hiding

3 double volume()

4 { double vol = width * height * depth;

5 return vol;

6 }

7 Box() // No argument constructor

8 { System.out.println("Initializing Box");

9 width = 10;

10 height = 10;

11 depth = 10;

12 }

13 }

1 class BoxDemo7

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

3  { Box b1 = new Box();

4 Box b2 = new Box();

5 double volume = b1.volume();

6 System.out.println(volume);

7 volume = b2.volume();

8 System.out.println(volume);

9 }

10 }

The user-defined no argument constructor would be called immediately after the object creation and would initialize the values of the instance variables width, height and depth to 10. Thus the output of the above program would be 1000 instead of 0 (Zero).

3. Parameterized Constructors

The no argument constructor defined in the previous example is not of much use as it always initializes with the same value. A constructor, which can take parameters, will be more useful.

this keyword:

Sometimes a method will need to refer to the object that invoked it. To allow this, Java defines this keyword. It can be used inside any method to refer to the current object. That is, this is always a reference to the object on which the method was invoked. You can use this anywhere a reference to an object of the current class’s type is permitted. To better understand what this refers to, consider the following example.

Instance Variable Hiding

As you know, it is illegal in Java to declare two local variables with the same name inside the same or enclosing scopes. Interesting, you can have local variables, including formal parameter to methods, which overlap with the name of the class’s instance variables. However, when a local variable has the same as an instance variable, the local variable hides the instance variable.

This is why width, height, and depth were not used as the names of the parameters to the Box() constructor inside the box class. If they had been, then width would have referred to the formal parameter, hiding the instance variable width.

While it is usually easier to simply use different names, there is another way around this situation. Because this lets you refer directly to the object, you can use it to resolve any name space collisions that might occur between instance variables and local variables.

Example: The following program defines a parameterized constructor, which is used for initializing the object.

1  class Box

2  { private double width, height, depth; //data hiding

3 double volume()

4 { double vol = width * height * depth;

5 return vol;

6 }

7 Box(double w, double h, double d) //Parameterized constructor

8 { System.out.println("Initializing Box");

9 width = w; height = h; depth = d;

10 }

11 /* Box(double width,  double height, double depth)  //Parameterized constructor

12 { System.out.println("Initializing Box");

13 this.width = width;

14 this.height = height;

15 this.depth = depth;

16 }*/

17  }

1   class BoxDemo8

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

3   { Box b1 = new Box(10,20,15);

4 Box b2 = new Box(3,6,9);

5 double vol;

6 double volume = b1.volume(); System.out.println(volume);

7 volume = b2.volume(); System.out.println(volume);

8 }

9  }

The parameterized constructor allows you to initialize the box with any dimensions.

4. Overloading Constructors

It is possible to overload the constructor just like methods. For example, the constructor of class Box can be overloaded to initialize different types of boxes. If we have a cube then we need to pass just one argument as all the sides of the cube would be of same dimension.

Example: The following program makes use of overloaded constructor to create and initialize the different type of boxes.

1  class Box

2  { private double width, height, depth; //data hiding

3 double volume()

4 { double vol = width * height * depth;

5 return vol;

6 }

7 Box(double w, double h, double d)

8 { width = w; height = h; depth = d;

9 }

10 Box()

11 { width = -1; height = -1; depth = -1;

12 }

13 Box(double len)

14 { width = height = depth = len;

15 }

16 Box(Box ob)  // Copy Constructor

17 { width = ob.width; height = ob.height; depth = ob.depth;

18 }

19  }

1 class BoxDemo9

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

3  { Box b1 = new Box(10,20,15);

4 Box b2 = new Box();

5 Box b3 = new Box(5);

6 Box b4 = new Box(b1);

7 double vol;

8 vol = b1.volume();

9 System.out.println(vol);

10 vol = b2.volume();

11 System.out.println(vol);

12 vol = b3.volume();

13 System.out.println(vol);

14 vol = b4.volume();

15 System.out.println(vol);

16 }

17 }

Java Method Overloading

We can have more than one method with the same name as long as they differ either in number of parameters or type of parameters. This is called method overloading as discussed earlier.

While calling an overloaded method it is possible that type of the actual parameters passed may not match exactly with the formal parameters of any of the overloaded methods. In that case parameters are promoted to next higher type till a match is found. If no match is found even after promoting the parameters then a compilation error occurs.

Example: The following program overloads the method area() to find the area of a circle, square, rectangle and  a triangle.

1  class Area

2  { static final double PI = 3.1415;

3  static double area(double radius) //area of circle

4 { return PI * radius * radius;

5 }

6 static float area(float size) // area of square

7 { return size * size;

8 }

9 static float area(float length, float width) // area of rectangle

10 { return length * width;

11 }

12 static float area(float a, float b, float c) // area of triangle

13 { float s = (a+b+c)/2;

14 float  area = (float) Math.sqrt(s * (s-a) * (s-b) * (s-c));

15 return area;

16 }

17 public static void main(String a[])

18 { double carea = area(3.0); //Circle’s area() method is invoked

19 System.out.println(carea);

20 float sarea = area(3.0f); //Square’s area() method is invoked

21 System.out.println(sarea);

22 float rarea = area(3.0f,4.0f); //Rectangle’s area() method is invoked

23 System.out.println(rarea);

24 float tarea = area(3.0f,4.0f,5.0f); //Triangle’s area() method is invoked

25 System.out.println(tarea);

26 // next higher type matching with the parameter is float

27 float area = area(3);  //Squares’s area() method is invoked

28 System.out.println(area);

29 area = area(3,4);  //Rectangle’s area() method is invoked

30 System.out.println(area);

31 area = area(3,4,5);  //Triangles’s area() method is invoked

32 System.out.println(area);

33 }

34 }