Saturday, 30 May 2015

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 }

Java Methods

Java methods are equivalent to C++ functions. Objects can communicate with each other using methods. Java’s methods can be classified in the two categories:


  • Instance Methods
  • Static Methods 


Just like static variables and instance variables, there are static methods and instance methods.

1. Instance Methods

The general form of an instance method is:

<return-type> <method-name> (parameter-list)

{

<method-body>

}

Method definition has four parts:


  • Name
  • Return Type
  • List of Parameters
  • Method Body

The return type can be a primitive data type or reference data type. In case, the method returns a 
reference, the return type will be the name of the class to which the object referred to by the returned reference belongs. It is must to declare the return type even if the method does not return any value. In this case, the return type should be declared as void.

The method’s formal parameters/arguments are specified within the parenthesis after the method name. The syntax is same as in C/C++.

The method body may contain any valid Java statement. If the method has a return type, then a value must be returned through return statement.

Invoking/Calling Instance Methods

The dot (.) operator is used to invoke/call the instance methods. The general form for calling the 

instance methods using the dot operator is: 

<object-reference>.<method-name>(paremeter-list)

Where <object-reference> is some reference variable pointing to an object and <method-  name> is the name of an instance method. For example, after creating an object of type Box and storing its reference in the reference variable b1, we can call the instance method  volume() using dot operator as follows: 

Box b1 = new Box();

b1.volume();

Instance methods can access the instance variables as well as static variables.

Example: The following program demonstrates how to call a instance method.

1 class Box 

2 { double width; //instance variables

3 double height;

4 double depth;

5 void volume() //instance method

6 { System.out.println("volume is:" + width * height * depth); 

7 }

8 }

1 class BoxDemo_4

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

3   { Box b = new Box();

4 b.width = 10; 

5 b.height = 20;

6 b.depth = 15;

7 b.volume();

8 }

9 }

In the main() method an instance of the class Box is created, its instance variables are initialized and then the instanced method is called. The instance method volume() calculates and displays the volume of the Box.

While accessing an instance variable inside main() method, we have used object reference. It is required, as we can not access an instance variable directly inside a static method. However, when an instance variable is accessed by a method that is defined in the same class as the instance variable, the instance variable can be referred directly. 

In fact we cannot specify the object reference in the method volume(), in the above example. This is due to the fact that unlike instance variables, there is only one copy of the instance methods. The instance methods use the copy of the instance variables of the object through which they are called. So the same method called through different object references will use different copy of the instance variables and hence the name instance method.

Implicitly an instance variable referred directly in a method uses this reference. For example, in the above program the direct reference to variables width, height and length is equivalent to this.width, this.height and this.length. The reference this inside a method refers to the current object (i.e. the object on which the method is called). The reference this is replaced by the reference of the invoking object at run-time. Hence the same instance method invoked through different objects will use different set of instance variables and hence will normally give different results.

Example: The following program demonstrates that calling non-static/instance method on different objects results in different output. 

1 class Box 

2 { double width; //instance variables

3 double height;

4 double depth;

5 void volume() //instance method

6 { System.out.println("volume is "+width*height*depth); 

7 }

8 }

1 class BoxDemo4

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

3   { Box b1 = new Box();

4 Box b2 = new Box();

5 b1.width = 10; b1.height = 20; b1.depth = 15;

6 b2.width = 3; b2.height = 6;  b2.depth = 9;
7 b1.volume();

8 b2.volume();

9   }

10 }

The first call to method volume() displays the volume of the box b1 correctly as 6000 and the 
second call to method volume() displays the volume of the box b2 as 162.

Method Returning a value

Example: The following program demonstrates use of method, which returns a value i.e. its 
return type, is not void.

1 class Box 

2 { double width;

3 double height;

4 double depth;

5 double volume()

6 { return width * height * depth; 

7 }

8 }

1 class BoxDemo5

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

3   { Box b1 = new Box();

4 Box b2 = new Box();

5 double vol;

6 b1.width = 10;

7 b1.height = 20;

8 b1.depth = 15;

9

10 b2.width = 3;

11 b2.height = 6;

12 b2.depth = 9;

13 vol = b1.volume();

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

15 vol = b2.volume();

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

17 }

18 }

Passing Arguments to Methods.

In the previous examples using class BoxDemo5, we initialized the instance variables directly to 
keep the things simple. This should not be done as it defeats the purpose of data encapsulation.

Moreover the instance variables can be made private so that they cannot be accessed from other 
classes. In that case it would not be possible to access the instance variables directly. The only 
alternative in that case is to define a method that takes width, height, and length as arguments 
and then initializes the instance variables.

Example: The following program defines two classes: Box and BoxDemo6. The class Box has a 
method that takes arguments. The classes may be defined in same source file or in two different 
source files. But in both the cases you will get two classes after compilation: Box.class and 

BoxDemo6.class. You can execute only class BoxDemo6.class as only this class has main() 
method. It also makes use of class Box for creating an instance/object and calling methods.

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. void setDimensions(double w, double h, double d)

8. { width = w;

9. height = h;

10. depth = d; 

11. }

12. /* Instance Variable Hiding 

13. void setDimensions(double width,double height,double depth)

14. { width = width;

15. height = height;

16. depth = depth; 

17. }

18. */

19. /* Instance Variable Hiding 

20. void setDimensions(double width,double height,double depth)

21. { this.width = width;

22. this.height = height;

23. this.depth = depth; 

24. }

25. */

26. }

1 class BoxDemo6

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

3    { Box b1 = new Box();

4 Box b2 = new Box();

5 b1.setDimensions(10, 20, 30);

6 double volume = b1.volume();

7 System.out.println(volume);

8 b2.setDimensions(5, 10, 15);

9 volume = b2.volume();

10 System.out.println(volume);

11 }

12 }

You cannot access the instance variables of class Box though object reference in the class 
BoxDemo6 as instance variables are declared private. The private instance variables can be 
accessed only in the class in which they are declared.

Nesting of Instance Methods

One instance method can invoke the other instance method of the same class without qualifying 
i.e. by just specifying the method name. For example, in the following program, calCost() 
method, which is an instance method, can call the instance method area() of the same class 
simply by its name.

1 class Circle

2 { static final float  PI = 3.1415f;

3 float puCost; // say cost of painting unit area

4 float radius;

5 float area()

6 { return PI * radius * radius;

7 }

8 float calCost()

9 {

10 float cost = puCost * area();

11 return cost;

12 }

13 public static void main(String args[])

14 { Circle circle = new Circle();

15 circle.puCost = 100;

16 circle.radius = 3;

17 float area = circle.calCost();

18 System.out.println(area); 

19 }

20 }

2. static Methods 

The static methods can be accessed like static variables through the class name without creating 
any instance/object. The static methods can also be called using the object reference. The static 
methods can directly access only static variables irrespective of the fact that they are invoked 
through class name or object reference.

The general form of a static method is:

static <return-type> <method-name> (parameter-list)


<method-body>


The general form is same as that of a instance method with the only difference that the modifier 
static is used before the return type.

Invoking/Calling static Methods

Example: The following program demonstrates the use of static method. The method area() 
takes one argument representing the radius of the circle and calculates its area. The method area() does not use any instance variable so it is declared as static and can be invoked through class name without creating any instance/object.

1 class Circle

2 { static final float  PI = 3.1415f;

3 static float area(float radius)

4 { return PI * radius * radius;

5 }

6 public static void main(String args[])

7 { int r = 4;

8 float area = Circle.area(r); 

9 //float area = area(r); //Nesting of static methods 

10 System.out.println("Area: "+area); 

11 }

12 }

Here the static variable PI is declared to be constant by putting modifier before the type. This is 
equivalent to const of C/C++.

Nesting of Class Methods

One class method can invoke the other class method of the same class without qualifying i.e. by 
just specifying the method name. For example, in the above program main() method, which is 
static can call the static method area() of the same class simply by its name: 

float area = area(r);

This nesting can go to any depth.

Java Variables

Java has three kinds of variables:


  • Local variables
  • Instance variables
  • Static Variables


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

1. Instance Variables

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

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

Initialization

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

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

length are initialized to 0 (Zero).

Accessing Instance Variables

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

<Object Reference>.<Variable Name>

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

box.width box.height box.length

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

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

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

We can use instance variables in expressions as shown below:

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

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

System.out.println(box.height);

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

1 class Box

2 { double width;

3 double height;

4 double depth;

5 public static void main(String args[])

6   { Box b = new Box();

7 double vol;

8 b.width = 10;

9 b.height = 20;

10 b.depth = 15;

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

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

13 }

14 }

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

Box.java

1 class Box

2 { double width;

3 double height;

4 double depth;

5 }

BoxDemo.java

1 class BoxDemo

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

3    { Box b = new Box();

4 double vol;

5 b.width = 10;

6 b.height = 20;

7 b.depth = 15;

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

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

10  }

11 }

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

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

Box.java

1 package p1;

2 class Box

3 { double width;

4 double height;

5 double depth;

6 }

BoxDemo.java

1 package p1;

2 class BoxDemo

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

4 { Box b = new Box();

5 double vol;

6 b.width = 10;

7 b.height = 20;

8 b.depth = 15;

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

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

11 }

12 }

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

java p1.BoxDemo

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

javac  -d . Box.java

javac  -d . BoxDemo.java

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

Box.java

1 package p1;

2 public class Box

3 { public double width; //instance variables

4 public double height;

5 public double depth;

6 }

BoxDemo.java

1 package p2;

2 import p1.*;

3 class BoxDemo

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

5    { Box b = new Box();

6 double vol;

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

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

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

10   }

11 }

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

javac  -d . Box.java

javac  -d . BoxDemo.java

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

(parent of p1 and p2):

java  p2.BoxDemo

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

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

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

Box.java

1 class Box

2 { double width; //instance variables

3 double height;

4 double depth;

5 }

BoxDemo2.java

1 class BoxDemo2

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

3  { Box b1 = new Box();

4 Box b2 = new Box();

5 double vol;

6 b1.width = 10;

7 b1.height = 20;

8 b1.depth = 15;

9 b2.width = 3;

10 b2.height = 6;

11 b2.depth = 9;

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

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

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

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

16    }

17 }

2. Static Variables

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

static double width;

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

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

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

<Class Name>.<Variable Name>

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

Box.width

Box.height

Box.length

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

box.width

box.height

box.length

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

Initialization

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

Box.java

1 class Box

2 { static double width;

3 static double height;

4 static double depth;

5 }

BoxDemo.java

1 class BoxDemo3

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

3    { Box b1 = new Box();

4 Box b2 = new Box();

5 double vol;

6 b1.width = 10;

7 b1.height = 20;

8 b1.depth = 15;

9

10 b2.width = 3;

11 b2.height = 6;

12 b2.depth = 9;

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

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

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

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

17  }

18 }

Java assigning object reference variables

The following example explains what happens when we assign one object reference to another object reference.

Example: 

Box b1 = new Box();

Box b2 = b1;

You might think that b2 is being assigned a reference to a copy of the object referred to by b1. That is, you might think that b1 and b2 refer to separate and distinct objects. However, this would be wrong.

Instead, after this fragment executes, b1 and b2 will both refer to the same object. The assignment of b1 to b2 did not allocate any memory or copy any part of the original object. It simply makes b2 refer to the same object, as does b1. Thus, any changes made to the object through b2 will effect the object to which b1 is referring, since they are the same object.

Although b1 and b2 both refer to the same object, they are not linked in any other way. For example, a subsequent assignment of null to b1 will simply unhook b1 from the original object without affecting the object or b2:

Box b1 = new Box();

Box b2 = b1;

.

b1 =null;

Here, b1 has been set to null, but b2 still points to the original object.

Note: When you assign one object reference variable to another object reference variable, you are not creating a copy of the object, you are only making a copy of the reference.

Java Allocating Memory using Operator new

The memory for Java objects is always allocated dynamically with the help of new operator. For
example, an instance/object of the class Box can be created as follows:

Box box = new Box();

For the sake of understanding we can compare new operator with the malloc() of C. In the above
example, new operator will allocate memory for an object of class Box and return its reference, which is then assigned to reference type variable box. The reference type variable box will now refer to an object of type Box as shown below:

The new Operator


It is important to understand that new allocates memory for an object during runtime. Since memory is finite, it is possible that new may not be able to allocate memory for an object because in-sufficient memory exists. If this happens, a run-time error will occur.

Java Declaring Objects

You can declare object of class Box as follows:

Box box;

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

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

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

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

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

Box box = null;

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