Sunday, 31 May 2015

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 }