0

Java is pass by value. What if I need a pass by reference. For example in the following code I need a pass by reference mechanism.

public class BinaryTree {
    public TreeNode root;

    public BinaryTree(){
        root = null;
    }

    public TreeNode insert(TreeNode temp,int x){
        if(temp == null){
            temp = new TreeNode();
            temp.key = x;
            temp.left = temp.right = null;
            return temp;
        }
        if(temp.key > x)
            temp.left = insert(temp.left,x);
        else if(temp.key < x)
            temp.right = insert(temp.right,x);
        return null;
    }
 }

When insert is called with root, I need root to be passed as a reference so as to change its value. But this does not happen in Java, since it's pass by value. In C/C++ the above could be easily achieved. Don't you think that this is a drawback of Java? How could such problems be solved in Java?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
nikhil
  • 9,023
  • 22
  • 55
  • 81
  • Java cannot pass by reference at all. Im not sure I completely understand your question, can you not use `this.root` for your example above? – ProfessionalAmateur Nov 13 '11 at 01:02
  • If you mean for `insert(null, n)` to create a new tree, set `root`. Returning null seems weird to me. – Dave Newton Nov 13 '11 at 01:05
  • 1
    @BalusC: What i mean is if i use the above code..what happens is that insertion into the tree happens successfully but since only a copy of root is passed to insert, root never gets updated and always stays null.. – nikhil Nov 13 '11 at 01:06
  • 3
    Even if you were to do this in C++, I would call you out on it. The logical thing here is, if you don't have a damn root, create a rootless ctor. If you want to specify root, accept one in an overload. Your messy if statement is solved via overloading. Additionally, I'd say that if root is null, set root on insert. That makes way more sense than what you're trying to do, and is one of the cases where Java coerces you in to doing something that makes more sense (especially to other people). – Doug Moscrop Nov 13 '11 at 01:11
  • @nikhil: Sorry, I have no idea what you are talking about. I just sanitized some poor English from your question so that it gets a bit more chance to survive and then ignored it further. Perhaps you're confusing me with someone else. I did not ever post an answer or a comment on this question (well, right now I do, but not before your comment-reply). – BalusC Nov 13 '11 at 02:59

4 Answers4

8

In Java, if you have a reference type the reference is passed by value.

Inside the method you can mutate the object that was passed and the caller will see those changes.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • Mutating an object means changing the state of the object, such as `temp.key = x;` in your example. – Mark Byers Nov 13 '11 at 01:06
  • ok fine..Now how would u go about changing the contents of root? I mean that only a copy of root is being passed and how can root be updated here? – nikhil Nov 13 '11 at 01:08
  • @nikhil By setting `root`? But I'm not convinced you should be passing in a node at all--don't you just want to insert a value into the tree and let the tree do all the node management? – Dave Newton Nov 13 '11 at 01:19
3

root can be changed by getting the return value.

public void insert(int x) {
    root = insert(root, x);
}

I changed the method insert(...) a little.

private TreeNode insert(TreeNode temp,int x){
    if(temp == null){
        temp = new TreeNode();
        temp.key = x;
        temp.left = temp.right = null;
    }
    if(temp.key > x)
        temp.left = insert(temp.left,x);
    else if(temp.key < x)
        temp.right = insert(temp.right,x);
    return temp;
}
wannik
  • 12,212
  • 11
  • 46
  • 58
3

Don't you think that this is a drawback of Java?

No. Because:

  1. There are few cases where you really need it.
  2. There are workarounds (see below).
  3. Implementing pass by reference in Java would be difficult. It makes code generation and garbage collection significantly more complicated.

(OK ... so really these are counter-arguments. But we are talking about a language design issue here, and any rational discussion of language designs has to weigh up the pros and cons of supporting a particular feature. And that includes implementation cost and performance issues.)

How could such problems be solved in Java?

The general approach is to restructure your code so that the variable you need to update in the called method is replaced with a reference to a mutable object or an array. This may entail the caller doing a bit more work, but that is generally acceptable.

Alternatively (and in your example) restructure the code so that call by reference is unnecessary.


In your example, there are two observations to make:

  • The "call-by-reference" mechanism is only used in the case where the tree is empty. It is not difficult to change this so that it is not necessary.

  • In fact, your use of call-by-reference, and in fact the entire insert method, is a leaky abstraction. There is nothing to stop you calling the method with a node object that is nothing to do with the current BinaryTree instance. You are relying on the caller to maintain the (implied) invariants of the tree.

The following version addresses both of these issues:

public class BinaryTree {
    private static class TreeNode { ... }

    public TreeNode root;

    public BinaryTree(){
        root = null;
    }

    public void insert(int x) {
        root = insert(root, x);
    }

    private TreeNode insert (TreeNode node, int x) {
        if (node == null) {
            return new TreeNode(x);
        }
        if (node.key > x)
            node.left = insert(node.left, x);
        else if (node.key < x)
            node.right = insert(node.right, x);
        return node;
    }
 }

(I don't exactly like the way that we reassign the left / right pointers at each level after the insertion, but it does make the insertion logic simple.)

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

Java is pass by value for everything. Whether you are working with primitives or with reference types.

The "value" or a reference type is the reference itself, so when using reference types the reference itself is passed.

Hunter McMillen
  • 59,865
  • 24
  • 119
  • 170