Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ References and Java References

Tags:

java

c++

//C++ Example

#include <iostream>
using namespace std;

int doHello (std::string&);
int main() {
    std::string str1 = "perry";
    cout << "String=" << str1 << endl;
    doHello(str1);
    cout << "String=" << str1 << endl; // prints pieterson
    return 0;
}

int doHello(std::string& str){
    str = "pieterson";
    cout << "String=" << str << endl;
    return 0;
}

In the above case, as expected the string 'str1' reference is modified when str reference is modified

//Java Example

public class hello {

    public static void main(String args[]){
        String str1 = "perry";
        System.out.println("String=" + str1);
        doHello(str1);
        System.out.println("String=" + str1); // does not prints pieterson
    }

    public static void doHello(String str){
        str = "pieterson";
        System.out.println("String = " + str);
    }
}

In Java, String str and String str1 are two different objects initially referencing the same String, so when we change str reference in doHello(), str1 reference does not get changed.

How can we achieve C++ style functionality in Java with Strings, Collections such as List, Vectors, other Objects.

Update:

Thanks Jon for a wonderful explaination, I believe any Java beginner will surely come across this question. Let me explain what problem i ran into while using lists.

//bad doHello() 

void doHello(List inputList) { 
    inputList = getListFromAnyFunction(); // wrong, didnt work 
} 

// good doHello 

void doHello(List inputList) { 
    inputList.addAll(getListFromAnyFunction()); // worked 
}

Thanks Powell and Harshath for your explainations and code samples.

like image 555
pankajt Avatar asked Jun 11 '09 07:06

pankajt


2 Answers

Java does not have pass by reference (which you were using in the C++ code) at all. The references are passed by value. (The values of str and str1 aren't objects at all, they're references - it really helps to keep the two concepts very separate.)

Typically you would use a return value to return a new reference if you need to:

str1 = doHello(str1);

Note that String is slightly different to List etc, because strings are immutable. To modify a collection (well, any mutable collection) you don't need to create a new one, you just modify the object via the original reference:

public static void addHello(List<String> items)
{
    items.add("Hello");
}

You could then call this like so:

List<String> list = new ArrayList<String>();
addHello(list);
System.out.println(list.get(0)); // "Hello"

The difference between mutating an existing object and changing the value of a variable to refer to a different object is crucial. If you want to leave the existing collection alone and create a new one, you'd have to do that explicitly:

public static List<String> withHello(List<String> items)
{
    List<String> newList = new ArrayList<String>(items);
    newList.add("Hello");
    return newList;
}

You'd then call it like this:

List<String> empty = new ArrayList<String>();
List<String> newList = withHello(empty);
System.out.println(empty.size()); // Prints 0
System.out.println(newList.size()); // Prints 1

Does this answer everything you needed?

like image 130
Jon Skeet Avatar answered Oct 27 '22 10:10

Jon Skeet


Parameter passing, call-by-reference and call-by-value (short answer)

In C++ there are two parameter passing forms, call by value and call by reference. (The better name for call-by-value is call-by-new-L-value, but I digress.)

In Java programs all parameters are passed by value. [There are some people that think that Java passes objects by reference, but they're wrong—see the long answer below—Java passes the reference value of Objects, but that is not the same thing at all.]

The value of a Java Object (and what is passed) is a pointer to the object (confusingly, but accurately, called a reference to the object), and calling a Java object method, for example, obj.meth(), de-references the pointer value of obj before calling the method on the object found there.

In C++ the same call would look like: obj->meth().

If you manipulate the object (for example, by calling a method on it) passed as a parameter to a method in Java, this may modify the object, and if the caller still has a variable holding that object it can see these changes. If you merely assign to the (local) parameter variable, you simply update the pointer stored in the local variable—the object is unaffected, and the caller will not notice this.

So, the short answer to your question is that Java passes by value, and the call-by-reference mechanism of C++ is not available in Java.

Parameters, variables and call-by-value (long answer)

To understand what's going on here we need to understand the mechanics of variables and parameter passing a bit more.

Variables

Generally speaking, a variable in a programming language is an identifier that is associated with a value. Variables that denote values manipulated at runtime (we are here ignoring macro variables, constants that are 'compiled away', and so forth) have to have two values associated with them. Here is an example that explains why:

int a = 0;
a = a + 1;

a is the variable, and in the line a = a + 1; it is referred to twice. Once, (on the right hand side of the =) the value 0 is meant and once, (on the left hand side of the =) the location of the value of a is meant (that is, where the integer value of a is stored). Only by accessing the location can the program update the value which is contained in it.

These two values associated with a variable are called the R-value and the L-value. (These names were invented by Christopher Strachey; I'm a fan.) Other constructs in the language refer to one or other of these values depending upon context. For example:

a[x-1] = x;

refers to the R-value of x twice (even though one is on the left-hand-side of the =), but only the L-value of a (or at least one of the elements of the array a).

In most programming languages, we explicitly manipulate the R-values of variables, and leave the compiler (from the form of the program) to manage the L-values automatically for us. We have to understand them a bit (in C, in particular with arrays, we assume a lot about L-values), but most of the time we don't have to know the mechanics.

Call by value

Look at this call:

int p=1;
obj.meth(p);
…
void meth(int a) {…a…}

What happens to the parameters here? First the R-value of p is calculated, then, when meth is 'entered', a new variable a is constructed. It is given a new L-value (this location is normally on a stack of some sort) and the R-value of the parameter is stored in the location.

Now, when a appears in meth it has the same R-value that p had (initially) and a new L-value. Changes to a's R-value make no difference to the variable p. This is called call-by-value (more properly, call-by-new-L-value).

Call by reference

Look at this C++ call:

int p=1;
obj.meth(p);
…
void meth(int& a) {…a…}

Here the L-value of the parameter p is calculated, and when the variable a is constructed it is “given” the same L-value as p. Then any use of a in the body of meth is just like a use of p. Assignment, for example will alter the stored value in p as well as (apparently) the value in a.

Java doesn't do this.

like image 22
Steve Powell Avatar answered Oct 27 '22 09:10

Steve Powell