Sunday, 31 May 2015

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