Java, pass-by-value, reference variables - java

I have a problem with understanding the "pass-by-value" action of Java in the following example:
public class Numbers {
static int[] s_ccc = {7};
static int[] t_ccc = {7};
public static void calculate(int[] b, int[] c) {
System.out.println("s_ccc[0] = " + s_ccc[0]); // 7
System.out.println("t_ccc[0] = " + t_ccc[0]); // 7
b[0] = b[0] + 9;
System.out.println("\nb[0] = " + b[0]); // 16
c = b;
System.out.println("c[0] = " + c[0] + "\n"); // 16
}
public static void main(String[] args) {
calculate(s_ccc, t_ccc);
System.out.println("s_ccc[0] = " + s_ccc[0]); // 16
System.out.println("t_ccc[0] = " + t_ccc[0]); // 7
}
}
I know that because s_ccc is a reference variable, when I give it to the method calculate() and I make some changes to its elements in the method, the changes remain even after I leave the method. I think that the same should be with t_ccc. It is again
a reference variable, I give it to the method calculate(), and in the method I change the referece to t_ccc to be that of s_ccc. Now t_ccc should be a reference variable pointing to an array, which has one element of type int equals to 16. But when the method calculate() is left, it seems that t_ccc points its old object. Why is this happening? Shouldn't the change remain for it, too? It is a reference variable after all.
Regards

There's an extended discussion of how Java passes variables at an earlier question "Is Java pass by reference?". Java really passes object references by value.
In your code, the references for the arrays (which are objects) are passed into calculate(). These references are passed by value, which means that any changes to the values of b and c are visible only within the method (they are really just a copy of s_ccc and t_ccc). That's why t_ccc in main() was never affected.
To reinforce this concept, some programmers declare the method parameters as final variables:
public static void calculate(final int[] b, final int[] c)
Now, the compiler won't even allow you to change the values of b or c. Of course, the downside of this is that you can no longer manipulate them conveniently within your method.

Here's a simple way to understand it.
Java always passes copies of arguments. If the argument is a primitive type (e.g. an integer), then the called method gets a copy of the primitive value. If the argument is a reference type, then the called method gets a copy of the reference (not a copy of the thing referred to).
When your main method begins, each of s_ccc and t_ccc refers to a distinct array.
This is the situation, where parentheses indicate variables and square brackets indicate the actual array structures:
(s_ccc) ---> [7]
(t_ccc) ---> [7]
Assuming that you meant calculate(s_ccc, t_ccc), then at the beginning of the calculate method:
(s_ccc) ---> [7] <---(b)
(t_ccc) ---> [7] <---(c)
Locals b and c are copies of globals s_ccc and t_ccc respectively.
Still within calculcate, after b[0] = b[0] + 9 has completed:
(s_ccc) ---> [16] <---(b)
(t_ccc) ---> [7] <---(c)
The zero (only) position in the array referred to by b has been modified.
The assignment c = b within calculate produces this situation:
(s_ccc) ---> [16] <---(b)
^------(c)
(t_ccc) ---> [7]
The local reference variable c, now contains the same reference as b. That has no effect on the global reference variable t_ccc, which still refers to the same array as before.
When calculate exits, its local variables (on the right-hand side of the diagrams) disappear. The global variables (on the left-hand side) were not used in calculate, so they are unaffected. The final situation is:
(s_ccc) ---> [16]
(t_ccc) ---> [7]
Neither c_ccc nor t_ccc were changed; each still refers to the same array as before calculate. Calling calculate changed the content of the array referenced by s_ccc, using a copied reference to that array (in b).
Local variable c started as a copy of t_ccc and was manipulated within calculate, but that changed neither t_ccc itself nor it's referenced data.

The method receives variables by value. Those values can't be changed (as far as the caller of the method sees), but the values contained within them can (if it's an object, or as in this case, an array).
So when you change the value b[0] inside the array, the change can be seen outside the method. However the line
c = b;
will change the value of c inside the method, but that change will not be seen outside the method, since the value of c was passed by value.

The line calculate(s_ccc, s_ccc); indicates you're not actually doing anything to t_ccc.
However, should this line have read calculate(s_ccc, t_ccc); than the effect remains the same.
This is due to the fact that you're assigning a new value to c here: c = b;
When assigning a new value to a reference argument the reference is lost.
This is the difference between altering a by reference variable and assigning a new value.

On entry to calculate(), b points at s_ccc and c points at t_ccc. Altering b[0] will therefore change s_ccc, as you've seen.
However, the assignment
c = b;
only points c at the same object b is pointing at, namely s_ccc. It does not copy the contents of what b points to to what c points to. As a result, t_ccc is unchanged. If you added the following line to the end of calculate():
c[0] = c[0] + 5;
s_ccc[0] would be 21.

Related

Why is it an error such that the x is considered an Object even though it is referencing an array?

Can someone help me understand this piece of code?
int[] A = new int[2];
Object x = A; // All references are Objects
A[0] = 0; // Static type of A is array...
x[1] = 1; // But static type of x is not an array: ERROR
According to the Oracle Java SE site:
In the Java programming language, arrays are objects (§4.3.1), are dynamically created, and may be assigned to variables of type Object (§4.3.2). All methods of class Object may be invoked on an array.
I understand that arrays can be assigned to Object type variables, however, my confusion perhaps lies in the concept of reference. When we say Object x = A, we are saying that x has a reference to the array A. However, my confusion lies in x[1] = 1. Why is it an error such that the x is considered an Object even though it is referencing an array? Do I think of [] as a kind of method that is only accessible in the "array" class?
While I would not unnecessarily throw away type information, you can use Array#setInt(Object, int, int) to access an int[] through an Object. That is,
Array.setInt(x, 1, 1); // x[1] = 1;
would work.
arrays are objects - This means that array for any type (reference or primitive) are the child class for Object class.
By using parent reference instance of child class can be accessed. Therefore the statement Object x = A; is syntactically correct.
By using Child reference child related methods/implementations can be accessed. Therefore the statement A[0] = 0; is syntactically correct.
By using parent reference child related methods/implementations cannot be accessed. Hence the statement x[1] = 1; is syntactically incorrect.

Pointers and objects in java

let's consider the following code:
public class Test {
private int a;
public Test(){
this.a = 1;
}
public static void main(String[] args) {
Test A = new Test();
Test B = A;
// TEST1
B.a = 0;
System.out.println(A); // prints 0
// TEST2
B = null;
System.out.println(A); // also prints 0
}
public String toString(){
return Integer.toString(this.a);
}
}
In TEST1, we modify B and then A is modified because B points to A.
I may understand why in TEST2 A doesn't become null, because B now points to null.
But the results of the two tests seem contradictory: why A doesn't become null ?
Thanks.
The variables A and B were both referencing the same object. B.a = 0 is altering that object. But when you reassign B = null, you're not altering the object. You're just altering the variable.
Test A = new Test();
The variable A points to an instance of type Test
Test B = A;
The variable B points to the same instance as variable A does.
B.a = 0;
The instance, variable B is pointing to (the same instance variable A points to), is changed.
B = null;
Variable B does not point to any instance anymore, while variable A still points to the same instance of type Test as before.
The main thing to understand is that variables A and B do hold a pointer to an instance of type Test. The instance of type Test is represented somewhere in memory and many variables may reference (point) to it.
The expression:
B.a = 0;
means: find the instance B is pointing at and modify its state in memory.
The expression:
B = null;
means: let B point to some other instance in memory (in your case to no instance at all). While the expression:
B = A;
means: let B point to the same instance in memory as A does point to.
By making object b null, you just cut the referance between the test object which resides in the heap and the B. The other referance between the test object and the A remains regardless of the other referances of the object unless you cut it or changed it.
regards
In Java variables are stored in the stack, while objects themselves are stored in the heap. Primitive type values are also stored in the stack, thus primitive type variables don't touch heap at all. But object variables on the stack contain heap addresses instead of values themselves. So by assigning null to B you change the B's (and only B's) value on the stack, but the heap value remains unchanged, and A's value on the stack remains unchanged, so A still references the same object in the heap allowing you to access its attributes and methods.

If arrays are object in java why the assignment between arrays is deep copy

If arrays are object as stated in Is an array an object in java then why the output of the code snipped below is [1,1,1]?
I thought after the execution of statement "a=b;" a and b are still pointing to the same content! Isn't it supposed to be shadow copy between objects?
import java.util.Arrays;
public class Local {
int [] a = null;
public Local(){
int [] b = {1,1,1};
int [] c = {5,5};
a=b;
b=c;// 'a' should change too as a and b are both objects! right?
}
public static void main(String[] args) {
Local local = new Local();
System.out.println(Arrays.toString(local.a));
}
}
Let me try to explain it line per line:
int [] b = {1,1,1};
On this line, three things happened.
Created a variable named b.
Created an array of int {1,1,1}
Assigned b to the array of intcreated on step 2.
int [] c = {5,5};
Same thing happened here
Created a variable named c.
Created an array of int {5,5}
Assigned c to the array of int created on step 2.
a=b;
Now we also assigned a to whatever the value of b is, which in this case is the array of int {1,1,1}
Now we have something like
b=c; // 'a' should change too as a and b are both objects! right?
What happened here is that we assigned b to whatever c's value is (int array {5,5}), now b is not pointing to {1,1,1} anymore and since Java is pass by value, a's value remained. It's not like a is pointing to the reference of b that whatever b is pointing to, a will point to it too.
Hope this helps.
// 'a' should change too as a and b are both objects! right?
No both a and b are just reference variables pointing to the same array object {1,1,1}.
With the below line you are making b to refer to altogether different array object where as a would still be pointing to the same array object {1,1,1} as the reference of only b but not a is changed by executing the below line
b = new int[] {2, 2};
Also by making a = b you are making them point to one single array object {1,1,1} and there is no deep/shallow copy happening here.
the variable a would not automatically update itself. mainly because
b = c //is like b = new int[]{5,5};
it is the same concept in your question earlier with
b = new int[]{2,2,2};
a is pointing to b's int array which is [1,1,1]
and you are telling b to point to c which is [5,5]
a => b's array
b => c's array
so a will retain its object and b will have a new one.
At first, b is pointed to the array object {1,1,1}
and you assign b to a, so a is pointed to {1,1,1}
so the out is {1,1,1}

If Java is pass by value, how does this swap method work? [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
OK so I understand that Java is pass by value (including for References, it passes the Object by the VALUE of the reference - i.e. the address).
If so then why does the swap(int[] array) method - passing an array of primitives - work?
public class TestArraySwap {
public static void swap(int a, int b) {
int temp =b;
b=a;
a=temp;
}
public static void swap(int[]a) {
int temp = a[1];
a[1]=a[0];
a[0]=temp;
}
public static void main(String[] args) {
//Test Primitive swap
int a=1;
int b=2;
System.out.println("a="+a +" b="+b);
swap(a,b);
System.out.println("a="+a +" b="+b);
//Test array swap
int[] array = new int[2];
array[0]=1;
array[1]=2;
System.out.println("a[0]="+array[0] +" a[1]="+array[1]);
swap(array);
System.out.println("a[0]="+array[0] +" a[1]="+array[1]);
}
}
The output is
a=1 b=2
a=1 b=2
a[0]=1 a[1]=2
a[0]=2 a[1]=1
The second swap works - I would expect it not to but perhaps I am missing something?
The main method has a reference to an array:
R1 ------> [1, 2]
Then it calls the swap() method. So a copy of the reference to the same array is created and used by the swap() method:
R1 -----> [1, 2]
^
|
R2 ---------|
Then the swap() method changes the content of the array:
R1 -----> [2, 1]
^
|
R2 ---------|
And it returns. R1 still references the same array, whose content has been changed.
After some more searching I found this answer
Array seems to be getting passed by reference in Java, how is this possible?
and of course the Java spec itself
In the Java programming language, arrays are objects
Everything in Java is passed by value (by copy).
swap(int[] a) works, because it passes (copies) only an address of the beginning of an array. Later it directly modifies memory under that address (a[0]) and the next one (a[1]).
swap(int a, int b) doesn't work, because it modifies copies of integers.
References in Java are something pointing to an object in heap. Arrays in Java are always allocated in heap. So arrays in Java are like normal objects.
References to objects in Java are stored in stack like primitive variables (int, long), it's a memory address stored in variable. So when they say that objects are passed by value, the literal meaning is that you copy address value into method parameters.
And for me this has always been confusing because though I do understand the process, I can't recall how it's properly named as
there are no references in Java
I'm always stuck when I hear the word 'value' applied to an object
The swap works because you pass the address (reference) of the array to the method. The method then operates on that array -- the same one the other method has a reference to.
I really don't like the statement, "Java is pass by value." I think it's really confusing.
public void methodA(){
int[] values = {1,2};
// MethodA stack frame has a register that contains a
// memory address (let's say it's 0x1F) that points to a contiguous section of
// memory sized for an integerarray of size 2.
methodB(values); // Pass the **memory address** (aka REFERENCE) not the register address
System.out.println(values[0]); // Prints "100"
}
public void methodB(int[] ints){
// MethodB stack frame now has a register with the memory address (0x1F)
// of 'ints' which is the same address that MethodA stack frame has.
// The same REFERENCE
ints[0] = 100; // Alter the value in mem of 0x1F+0
ints = new int[2]; // The local register overwrites the memory address of
// the REFERENCE value that was there with
// a new memory address -- say 0x5A
// since it's not storing it in the same register
// as MethodA, MethodA will not reflect this.
}

Only array is being modified

This is the code I have, please look at it before you read the question
package ict201jansem2012;
public class Qn3b {
public static void main(String[] args) {
int a = 1;
int b[] = {4,5};
String s = "Good luck!";
method1(b[1]);
System.out.println("(1) b[0] = "+b[0]+"; b[1] = "+b[1]);
method2(b);
System.out.println("(2) b[0] = "+b[0]+"; b[1] = "+b[1]);
method3(a);
System.out.println("(3) a = " + a );
method4(s);
System.out.println("(4) s = " + s );
}
public static void method1(int b) {
b = 7;
}
public static void method2(int[] b) {
b[0] = 3;
}
public static void method3(int a) {
a = 3;
}
public static void method4(String s) {
s = "UniSIM";
}
}
Output:
(1) b[0] = 4; b[1] = 5
(2) b[0] = 3; b[1] = 5
(3) a = 1
(4) s = Good luck!
So my question is ,
This is intresting for me to know as learning programmer. The int b array 0 index value has changed, but not the other variables like the String s and int a. Before i ran this program I roughly thought in my mind that the variable will change their values as the methods are called ,this is because the method is being called and the main method vairable such as a,s and b array are passed and then they are being modified.
So in a nutshell why is that the b array 0 index is changed while the other variables are not changed?
Because you said you were a beginner programmer, I'll do a little writeup to explain (or try to explain) exactly what is happening.
It is because you are passing an argument to your method1 - method4 methods
These arguments, themselves, are references to other objects.
When you use the assignment operator, an equals sign, you overwrite that reference for the value in the current scope - where variables can be 'seen'.
In your code:
In the case of method1 you are creating a new reference, the variable can only be seen within that scope. That is, when you then go b = << expr >> you are assigning the variable b within method1's scope the value, not b in the main scope. The same is true of your method3 and method4 methods, you are assigning a new value to the respective variables within that scope, as you are creating new references rather than altering the original objects.
But, method2's code behaves differently, this is because you are mutating the object inside that code. You are altering the object directly - rather than creating a new reference inside that scope.
Consider the code below
int[] array = new int[] {1, 2};
public void test()
{
method1(array);
System.out.println(array[0] + ", " + array[1]);
method2(array);
System.out.println(array[0] + ", " + array[1]);
}
// because we are working with objects, the identifier, can be different to the arrays identifier
// in this case, I've chosen to use 'a' instead of 'array' to show this
public void method1(int[] a)
{
// this mutates the array object
a[0] = 2;
}
public void method2(int[] array)
{
// this overwrites the method2.array but not the global array
array = new int[] { 1, 2, 3 };
}
We create a new array, with identifer 'array' in the global scope. (In Java, this would be the classes own scope)
In method1, we take an argument, which is the same object being passed as the global array object, so when we mutate it, both objects will change. So, the first print statement will be
"2, 2"
Where array[0] has been altered
N.B. Because we dealing with objects, the 'name' of the variable doesn't matter - it will still be a reference to the same object
However, in method2, we take an argument, like in method1, but this time we use the assignment operator to assign that variable to a new value in the scope that it's currently in - so the global array isn't altered, so we still print out
"2, 2"
For a beginner programmer, I would personally write a few test programs where you get to fully understand how variables and scopes work.
But just know, everytime you create a new block of code, a new scope is created, local variables to that scope can only be seen in that scope and ones below it.
For instance:
public void test()
{
int a = 5;
method1(a);
System.out.println(a); // prints 5
}
public void method1(int a)
{
// a is only viewable in the method1 scope
// and any scopes below it, that is, any scopes created within method1
// and since we use an assignment operator, we assign method1.a a value, not global 'a' a value
a = 123;
if (true)
{
// this is a new scope, variables created in this block cannot be seen outside it
// but can see variables from above it
System.out.println(a); // prints 123
}
}
Here, we create a new scope inside method1 inside the if statement, which can see a above it. However, because method1 and test's scopes are both independent, when we use the assignment operator, we assign the value of a to the local scope. So a is different in both test and method1
I hope you understand better now.
I'm not very good at conveying things, but if it even helped a little bit in understanding scopes I did well, plus, it was fun.
Java is pass-by-value, but most values (everything that's not a primitive, in this case int[] and String) are references, which means they act like pass-by-reference.
Here's a nice writeup: http://javadude.com/articles/passbyvalue.htm
arrays are special type of objects and memory will be allocated on HEAP. When you pass array as parameter to method it will be pass as reference-value (copy of the reference).
This means initial b and this new reference points to same object. Unless new reference points to another object, changes on this reference will reflect on same object. That is why you are seeing value reflected on original array.
All of the values were passed TO the inner methods, but the inner methods returned nothing. However, method2 modified the internal value of the array that was passed to it, so that inner value appeared modified on return.
Note that method2 is the only one where you did not assign to the variable (parameter) itself, but rather assigned to an element of the object whose reference was passed in.
There is a critical difference between modifying the reference (pointer) to an object, and modifying the object itself.

Categories