Page 1 of 1

Passing objects to a method Rate Topic: -----

#1 smohd  Icon User is offline

  • Critical Section
  • member icon


Reputation: 1752
  • View blog
  • Posts: 4,409
  • Joined: 14-March 10

Posted 21 June 2011 - 07:13 PM

*
POPULAR

Is this what you were expecting?
Java passes everything by value. When you pass primitive data type variables into a method, you get a distinct copy of it inside method. And this is what we expect when we talk about pass by value. The same happens when we pass handles to a method, we get a copy of a handle. But many java users takes that the handle is the object! When someone thinks like this, is when he gets what he was not expecting. Letís examine the following simple example:
public class ObjectPass {
    private int value;
    public static void main(String[] args) {
        ObjectPass p = new ObjectPass();
        p.value = 5;
        System.out.println("Before calling: " + p.value);
        increment(p);
        System.out.println("After calling: " + p.value);
       
    }
public static void increment(ObjectPass a){
        a.value++;
    }
} 

This is the output:

Quote

Before calling: 5
After calling: 6

Now it is like the pass was by reference! But the thing is what we pass exactly is a handle of an object, and in the called method a new handle created and pointed to the same object. Now when more than one handles tied to the same object, it is known as aliasing.
From the example above you can see that both p and a refer to the same object, to prove this try to System.out.println(p) and System.out.println(a) you will see the same address.

Why this?
This is the default way Java does when passing the handle to a called method, create alias. When you pass argument just to manipulate its value and not doing any changes to it, then you are safe. Instead, you need to make yourself clear by a creating a copy of the object inside method since by default Java doesnít do it for you.

Make a copy of it:
Aliasing happens automatically during argument passing. And if you are only reading information from an object and not modifying it, passing handle is the most efficient way. But sometimes you need to modify the value without affecting the caller object! Then here you must have a distinct copy of your object inside method.
Many languages like C++ support the ability to automatically create a local copy of object to a method. In java, this is not so, but instead you can use clone() method to perform the work. This is a method defined as protected in Object class which you have to override as public in every class that you want to clone its objects. Many collection classes like Vector class override this method.
Clone() method returns Object which must then be recast to proper type, also it throws CloneNotSupportedException which must be caught or thrown. When exception thrown means the object's class does not support the Cloneable interface.

How to make your class cloneable:
Even though clone() is defined inside object class, the cloning is not automatically available in every class unless the class implement Cloneable interface. So I have two things to do, first to implement Cloneable interface (My previous class header now will look):
 public class ObjectPass implements Cloneable { 

Also I need to override clone() as public like regarding that the first statement of it must be calling super class clone(), then may follow my own customization. This makes sure an exact duplicate is made:
 public Object clone() {
        try {
            return super.clone();
        }
        catch (CloneNotSupportedException e) {
            System.out.println("This object canít be cloned");
            return null;
        }
    } 


Now I can clone my objects so that I get a copy of it! Letís me change the increment() method, I want it to change its own copy of object without affecting outer object. The method should look like this now:
  public static void increment(TestObjectPass a) {
        a = (TestObjectPass) a.clone(); 
        a.value++;
    } 

Here I first clone the argument and assign to the same handle, then when I change its value, wow! It does not affect outside object. You can try to run it using updated code and see what you get :)

Shallow copy versus deep copy:
That override clone() is not enough when our class contains another object as its instance variable. Letís look at this example:
 class Value {

    private int num;

    public Value(int num) {
        this.num = num;
    }

    public void increse() {
        num++;
    }

    public String toString() {
        return num + "";
    }
}

public class Test implements Cloneable {

    private Value v = new Value(3);
    
    public void changeValue() {
        v.increse();
    }

    public Object clone() {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("This object cant be cloned");
            return null;
        }
    }

    public String toString() {
        return v + "";
    }

    public static void main(String[] args) {
        Test t = new Test();
        Test t2 = (Test) t.clone();
        System.out.println("t before t2 changes: " + t);
        t2.changeValue();
        System.out.println("t after t2 changes: " + t);
    }
} 


Since we clone, we are expecting that the change to one object should not affect the change to another object. But this is not the case, the output is:

Quote

t before t2 changes: 3
t after t2 changes: 4

This also will happen if a vector object passes another object in its collection and is known as shallow copy.
In order to get a copy of all things here, known as deep copy, a little bit work have to be done. Addition cone to clone() is needed to make it work as we are expecting. Instead of just returning a reference created by Object`s clone() method, first we modify the Test object returned and make sure its instance (of Value type) is also cloned. This will be achieved by first overriding clone() in class Value also since we need to clone its object as how we did in Test class. Then after receiving Test object from Object`s clone() method we clone() its Value also and the clone() method in Test class should look something like this:
 public Object clone() {
       Test temp = null;
        try {
            temp = (Test) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("This object canít be cloned");
        }
        temp.v = (Value) v.clone();
        return temp;
    } 

When you run this again, the output is:
[quote] t before t2 changes: 3
t after t2 changes: 3 [quote]

Donít need clone down hierarchy?
Stop it, but how? When super class implements cloneable and you need subclass objects not to be cloned, many ways have been suggested but simply to can either throw CloneNotSupportedException yourself in your override clone() [as in code below] or make your class final which will prevent down extension.
 public Object clone()
      throws CloneNotSupportedException{
          throw new CloneNotSupportedException();
      } 


This is the end of this tutorial about passing objects to methods, hope you have benefit and see you around.
[Some Java programmers feel that you should avoid clone altogether and instead implement another method for the same purpose!]

Is This A Good Question/Topic? 8
  • +

Page 1 of 1