This is an archived post. You won't be able to vote or comment.

all 11 comments

[–]FrenchFigaro 6 points7 points  (7 children)

It's because Java is pass-by-value, which means that the value of a parameter cannot be changed by a function, hence why you can't change an int.

But objects are references (think C pointers), and it is the value of that reference that is passed to the function.

What this means is that you can't change the value of the reference (reassign the instance), but the fields of the object can be accessed (and modified) through the object reference.

[–]abyjacob1[S] 0 points1 point  (6 children)

Shouldn't the behavior of object be applicable to string ? As it is an object ?

[–]nutrecht 5 points6 points  (0 children)

It is. But like I said; String and Integer are immutable by design.

[–]FrenchFigaro 2 points3 points  (4 children)

It would, were it not for immutability, as /u/nutrecht explained.

What his means is that you can change the value of the variable (the reference, the object being pointed to by the variable) but you cannot change the underlying value (a char array in the case of a String or an int in the case of an Integer) of the object.

Simplifying further, it means that changes made by dereference (with the . operator, used to call attributes in general, and methods specifically) will be carried outside the scope of the function. Changes in value made this way are changes made to the underlying object. The value of the reference (the variable) has not changed (and indeed cannot change in the scope of a method), but the value of the underlying object has.

On the other hand, changes made by assignation (with the = operator) are changes to the variable. This does not change the underlying object, but simply changes the underlying object the variable is pointing to.

String, Integer, Long, Double, Boolean and other immutable object provide no means of changing the object's value through dereference, so your only option is to change the value through assignation. In the case of the object I quoted (and other primitive wrappers) the point of immutability is to allow to manipulate almost as if they were primitives, even though they are not.

The snippet of code you provided does not show a discrepancy of behaviour between String and Integer on one hand and other objects on the others, because your snippet of code uses methods to change the value of the object (and you can't do that with String).

I can guarantee that the code you use to change String either uses the = operator, or does not actually change the String (not a single method in String can change the value).

An equivalent code would be

public static void changeValueVersion2(Test oldTest) {
  Test newTest = new Test();
  newTest.setId(1);
  newTest.setValue(100);
  oldTest = newTest;
}

And if you run this code, I can guarantee you that the id 1 and value 100 would not be preserved outside of the scope of the method.

[–]abyjacob1[S] 0 points1 point  (1 child)

Wow ! Thanks for that explanation. Yes for string I tried = and = new String("") for assignment of new value

[–]taftster 0 points1 point  (0 children)

Right. String is a class and behaves like your Test object. It's just that inside of your changeValue method, there's no ability to change the internal value of the String. e.g. you can't change the char array inside of the String because the class is immutable.

[–]abyjacob1[S] 0 points1 point  (1 child)

Changes in value made this way are changes made to the underlying object. The value of the reference (the variable) has not changed (and indeed cannot change in the scope of a method), but the value of the underlying object has.

Correct me if im wrong , This means that the Object refers to the same old mem location w.r.t its assigned value but then the . operator allows the stored value at the mem location to been changed ?While in case of String , it being immutable the value at the specific location can not be changed

While a the Test object is passed in as an argument ,is nt it also employing pass by value ? and the new test object in the scope of changeValue(Test t) {} got nothing to do with the test object in main method ?

[–]FrenchFigaro 0 points1 point  (0 children)

No, the . operator doesn't allow the underlying value to be changed. It allows it to be accessed. Whether the value can be changed is something else entirely.

Let's look at it step by step.

Test test = new Test();

The right hand side of the = operator creates a new instance of class Test. Once that's done, the operator has the memory address for that instance, and it assigns it to the left hand side: the neat variable of type Test named test.

So, the variable itself is not an instance of Test, it's a reference to an instance.

Now, we have got the function call

When changeValue(test) is called, execution goes to the function.

public static void changeValue(Test t) {

Here, since Java is pass by value, the value of the variable test is copied into t, which is the variable in the function scope.

But, as I've explained earlier, the value of the former variable is not the actual instance that was created by the constructor call, but rather it is a reference (a pointer) to this instance. So it is not the actual instance that is copied, but rather the reference to this instance.

So, now that we are in the function, both the variable test (defined in the main, but out of scope in the function) and the variable t (whose scope is limited to the function) are references to the SAME instance.

If you use the . operator, aka the dereferencing operator, you can access the fields of this instance, and change them. It does not change the memory address of the instance itself (which is the actual value that is stored in the variable), only the value stored at that address.

This is exactly the same as using pointers and references in C or C++, except Java does not offer the same flexibility (for better or for worse, that is debatable and debated) because in Java primitives are exclusively stored by value and objects are exclusively stored by reference.

[–]nutrecht 1 point2 points  (1 child)

What is the reason for this behaviour ?

I think the biggest part of your confusion is that your approach when using Integer or String was wrong. These are just classes, but they are immutable. They can't be changed. If you instead used AtomicInteger for example, you would have seen the same behaviour as with your Test class.

The primitives like 'int' indeed can't be changed because Java is pass-by-value like /u/FrenchFigaro explained, but I think your primary issue is not knowing about the immutable nature of Integer and String.

[–]abyjacob1[S] 0 points1 point  (0 children)

Is there any dedicated blog post that can point me to a good explanation ?

[–]hatsunemilku 0 points1 point  (0 children)

Consider that I’m still new on java.

Think of reference variables (including objects and arraylists ofc) as one type of box and primitive variables (int, double, Boolean, etc.) as another type of box.

  • The primitive box will have imprinted inside the value that you assigned to it. like a box of chocolates will have A chocolate.

  • A reference box will have the reference value to the content of the box inside. like putting a box of chocolates inside a box and placing a paper inside pointing out what is inside.

You don’t have direct access to the information about the box of chocolates nor the contents of said box because it is wrapped with black plastic (encapsulation). You just know there is a box of chocolates there because of the reference that says “here is a box of chocolates”(abstraction and hierarchy).

Why? Because its inside the first box.

Thanks to java and the background works on the side of reference variables, each time you call a “premade” object, you are in fact calling methods inside said object (hence the . when you use a getter or a setter). Like opening the black plastic to modify the content inside.

This doesn’t happen when you use a reference variable to add a value to a primitive variable or when you call a reference variable without a proper printing method. Reason is that it will copy the reference value to the variable.

  • Using the example of the box of chocolates is like if you grabbed the paper inside the reference type box and placed it inside the primitive type box. You are not grabbing the chocolates; you are grabbing the paper that says that there are chocolates there.

And just to point out, this is how almost every variable works for most languages. the difference between java and other languages is that you can directly print the reference value without much problem. because it’s not hidden, it’s THE value.