java pass array to methods in this code [duplicate] - java

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 4 years ago.
Is arrays passed by reference to methods in java? If so, why the following code prints 1,2,3,4,5 instead of 5,4,3,2,1 ?
public class Test {
public static void main(String[] args) {
int[] oldList = {1, 2, 3, 4, 5};
reverse(oldList);
for (int i = 0; i < oldList.length; i++) {
System.out.print(oldList[i] + " ");
}
}
public static void reverse(int[] list) {
int[] newList = new int[list.length];
for (int i = 0; i < list.length; i++) {
newList[i] = list[list.length - 1 - i];
}
list = newList;
}
}
enter image description here

Reference variables, not array variables
Your oldList, list, and newList variables are all references, references that point to an array floating around in memory someplace. The references are not in themselves an array. Each of those three variables could be made to refer to a different array with a call such as oldList = { 97, 98 , 99 } ;. Assigning a different array to a reference variable does not affect the content of the originally-assigned array.
In other words, oldList, list, and newList are not “array variables”, they are “reference variables” that happen to point to some array or another.
Conceptually, you can think of it as shown in this diagram.
So your line:
list = newList;
…has no beneficial effect. It does indeed re-assign the argument reference variable list from pointing to the blue first array to pointing to the salmon/yellow second array. But immediately after that re-assignment, the method ends. As the method ends, the list variable goes out of scope, and disappears. That leaves the second array dangling out in memory in limbo, eventually to be garbage collected as no more references remain pointing to it. So no lasting effect. That re-assignment of list has no effect on oldList, contrary to your apparent expectation.
The upshot is that after calling reverse(oldList);, you ended up with the same state as where you started, a reference variable oldList pointing to the original array.
To get your desired results you could choose either of at least two other approaches:
In the reverse method, make a new sorted array, and then when done, write those same sorted values back into the passed array. Let the new sorted array go out of scope when the method ends, to become a candidate for eventual garbage collection.
Define the reverse method to return an array, rather than return void. The calling method can then re-assign its own reference variable to point to the returned array.oldList = reverse( oldList ) ;
I recommend the second approach, generally-speaking. The first alternative is usually a bad idea; messing around with passed values tends to lead to confusing logic. Usually better to give results back to the calling method, and let the calling method decide what to do with those results. This approach promotes loose coupling.
All of this is a fundamental piece of understanding Java and object-oriented programming. It will be tricky to grasp at first. Keep at it until it suddenly it snaps into place in your mind, then becoming second-nature, a barely conscious part of your thinking while programming.
By the way, while irrelevant to your direct question about learning the intricacies of Java and OOP, I want to mention that in practice for real-work I would accomplish your task with different code. I would use the Java Collections framework such as List interface and ArrayList concrete class rather than simple arrays, with Integer class rather than int primitive, assisted by auto-boxing and the new List.of convenience method.
List < Integer > numbers = new ArrayList <>( List.of( 1 , 2 , 3 , 4 , 5 ) );
Collections.reverse( numbers );
The List.of result is immutable, and cannot be re-ordered. So I feed its elements to an modifiable ArrayList object’s constructor. The Collections.reverse method modifies the ArrayList, unlike with simple arrays.
Dump to console.
System.out.println( numbers );
[5, 4, 3, 2, 1]

Because Java is pass-by-value.
The value of the "reference" to the array is copied into the local variable list. When you reset that local variable list you do no more than reset the reference copied into list. You don't reset the reference being held by oldList.
so, to make it clear, I'll show a second example
public static void main(String[] args) {
int five = 5;
doSomething(five);
System.out.println("five is " + five);
}
public void doSomething(int number) {
number = number - 3; // This overwrites the number which is scoped
// to this block. Java passes by value, so
// the variable five is unaffected.
}
While this seems obvious for integers, it also holds for references to objects.
public static void main(String[] args) {
my name = "Edwin"; // a String object.
doThing(name);
System.out.println(name); // guaranteed to print "Edwin"
}
public void doThing(String value) {
value = "Not Edwin"; // impacts value, but only in this block
// which means name is unaffected
}

Related

code is not working as expected; array doubling; pass by reference [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 3 years ago.
i was working on stacks when i came across a problem where i had to double the array. i used this code which did not work but it should have.
class ArrayDouble
{
public static void main(String []args)
{
int arr[] = new int[10];
sizeChange(arr);
for(int i=0;i<arr.length;i++)
System.out.print(arr[i]+ " ");
}
public static void sizeChange(int arr[])
{
arr[0]=1;
arr = new int[2*arr.length];
arr[1]=1;
}
}
from what i have seen, any changes that takes place in an array which has been passed as a parameter, the changes reflect back in the actual parameters right? So why doesn't the change in size of the array is reflected in the original parameter?
Also, arr[0] becomes 1 in the original array but arr[1] remains 0. why does that happen?
PS: the problem was solved when i changed the return type of sizeChange to int[] and passed arr of sizeChange and collected it into the Main arr. So i dont need the correction of the code, i just need the answer as to why this is happening.
Thank you in advanced.
Arrays are not a primitive type in Java, but they are not objects either ... "
In Java, the called method can update the contents of the array, and it can update its copy of the array reference, but it can't update the variable in the caller that holds the caller's array reference. Hence ... what Java is providing is NOT pass-by-reference.
Like all Java objects, arrays are passed by value ... but the value is the reference to the array. So, when you assign something to a cell of the array in the called method, you will be assigning to the same array object that the caller sees.
This is NOT pass-by-reference. Real pass-by-reference involves passing the address of a variable. With real pass-by-reference, the called method can assign to its local variable, and this causes the variable in the caller to be updated.
Detailed Explaination :
Arrays are in fact objects, so a reference is passed (the reference itself is passed by value, confused yet?). Quick example:
// assuming you allocated the list
public void addItem(Integer[] list, int item) {
list[1] = item;
}
You will see the changes to the list from the calling code. However you can't change the reference itself, since it's passed by value:
// assuming you allocated the list
public void changeArray(Integer[] list) {
list = null;
}
If you pass a non-null list, it won't be null by the time the method returns.

Helper Methods within static method are overidding multiple variables? [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 5 years ago.
public class SeamCarving {
public static Seam carve_seam(int[][] disruption_matrix) {
int[][] original = disruption_matrix;
int[][] weighted_matrix = disruption_matrix;
SeamCarving s1 = new SeamCarving();
weighted_matrix = s1.buildMatrix(disruption_matrix);
....
}
In the above code I have a static method carve_seam. The method takes a matrix. That input is saved in a matrix variable called original. A calculation is performed on the matrix and that is also saved as a variable called weighted_matrix. Both are needed.
Since its in a static method, a new object of the class is made and it is called from that "s1.buildMatrix"
However, that line is doing something that is over my head. This is because afterwards, not only is weight_matrix changed (correctly from the buildMatrix method) but original is also changed to the same exact thing! How does this happen???
First thing you need to understand here is that all the three reference matrix, are referring to the same object you have passed as the input (disruption_matrix object). This is the reason why also the original and weighted_matrix are being changed.
In the first line,
int[][] original=disruption_matrix;
refers to the same object in disruption_matrix.
Then on the next line,
int[][] weighted_matrix=disruption_matrix;
refers to the same old object as well. So, you do not need to reach the line,
weighted_matrix = s1.buildMatrix(disruption_matrix);
to see that both original and weighted matrix have been changed. Actually the they have been changed when you have done the calculation to the disruption_matrix itself.
This situation is quite similar to a something like, where,
int a=10;
int b=a;
int c=a;
So, not only 'a' but also 'b' and 'c' will have their value assigned to 10.
In a OOP manner, where such same object is being assigned to different references, once a change has been made to the object through a single reference no matter that you're accessing the object through a different reference, the object has been changed.
For an example let's take this simple class,
Class A{
int val=10;
}
now, in some method we create an object and assign it to references,
A a=new A();
a.val=20;
A b=a;
b.val=30;
A c=a;
c.val=40;
As for the above code, an object is created under the reference called 'a'. In the next line, the value 'val' is accessed through that reference and has been changed from 10 to 20.
Then, the reference 'b' has been declared and it is initialized and pointed to the same object which 'a' is holding. Then in the next line, the value of that object (val) is changed again 20 to 30, but this time through 'b' instead of the reference 'a'.
Same goes to the next three lines where the value of the object is being changed from 30 to 40 through the reference 'c'.
So finally what will be the output?
System.out.println(a.val);
System.out.println(b.val);
System.out.println(c.val);
It is obviously going to give you the output,
40
40
40
This is the concept you are missing here (Pass by value and pass by reference).
In Java, Arrays are technically objects and not primitives, even for arrays of primitive types. Whenever you pass an argument to a method as an object, Java passes it as a reference; the values of the original argument change because all variables you have created are "referring" to the same object. This, however, is not the case with primitives, which are passed by value.
I suggest that whenever you need to make a matrix off of another you use the following utility method:
public static int[][] copyMatrix(int[][] original) {
int[][] copy = new int[original.length][];
for(int x = 0; x < copy.length; x++) {
copy[x] = new int[original[x].length];
for(int y = 0; y < copy[x].length; y++) {
copy[x][y] = original[x][y];
}
}
return copy;
}
At the end, your code would look like this:
public class SeamCarving {
public static Seam carve_seam(int[][] disruption_matrix) {
// no need to make an "original" variable anymore,
// since disruption_matrix already stands for it
int[][] weighted_matrix = copyMatrix(disruption_matrix);
SeamCarving s1 = new SeamCarving();
weighted_matrix = s1.buildMatrix(disruption_matrix);
....
}
}
Keep in mind that this implementation copies the arrays but not the objects. This will solve your problem when working with primitives like int but not with mutable objects.

Passing Arrays to a method inconsistent with passing primitive data type to a method

I understand that passing an array to a method is still Pass-By-Value, however the "value" that is passed is the reference of the array. This implies that changing the contents of the array would cause the contents to get updated in an earlier frame (if it's a recursive algorithm), or when it goes back to the main method, for that matter.
import java.util.Arrays;
public class SameArrayPassedOn{
public static void main(String[] args) {
int[] a = {1,1,1};
print(a);
fun(a,0);
print(a);
}
static void fun(int[] b, int count)
{
if(count == 1)
return;
b[0] = b[1] = b[2] = 2;
fun(b,1);
}
static void print(int[] a)
{
for(int x : a)
System.out.print(x + " ");
System.out.println("");
}
}
Output 111 222
However, if you create a new array, like for example, in the code below, since the reference is changed, the updates won't be reflected when you go back to the main method.
import java.util.Arrays;
public class NewArrayCreatedAndReferencePassedOn{
public static void main(String[] args) {
int[] a = {1,1,1};
print(a);
fun(a,0);
print(a);
}
static void fun(int[] b, int count)
{
if(count == 1)
return;
int[] newb = {2,2,2};
fun(newb,1);
}
static void print(int[] a)
{
for(int x : a)
System.out.print(x + " ");
System.out.println("");
}
}
Output 111 111
However, my question is, why such a design was chosen for Arrays. Why couldn't it be that, just like for a primitive data type, say, integer variable, a new int is created every time it's passed inside a function, although we are not explicitly creating a new int, or declaring one. Like for example,
import java.util.Arrays;
public class SameIntPassedOn_ButNewCopyCreatedEachFrame {
public static void main(String[] args) {
int i = 0;
fun(i);
}
static void fun(int b)
{
System.out.println(b);
if(b == 10)
return;
b = b+1;
fun(b);
System.out.println(b);
}
}
Output
0 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1
Had the same been done for arrays, it would've allowed us to have a different copy of the array for each frame of the recursive function, which would've been very handy.
I think it would've been nice to have uniformity in behavior, because at the moment, it looks as though, to achieve the same behavior with Arrays, as is exhibited by primitive data types, such as int, float etc, when passed to a method, it is necessary to use a 'new' keyword, and create a new array before passing on to the method.
However, my question is, why such a design was chosen for Arrays.
There are several main reasons.
The first is performance - it would lead to extremely poor performance if a new copy of the array had to be created every single time a method was called on it, especially for recursive calls.
Had the same been done for arrays, it would've allowed us to have a
different copy of the array for each frame of the recursive function,
which would've been very handy.
The second is that you already have the option of passing a copy of the array if you want to - you can create a copy manually and pass that. This way the programmer has the most control - they can choose to let method calls modify the array, or they can choose to pass a copy, allowing each method call its on version of the array to work with. If we forced the programmer to use a copy all the time, they would lose the option of letting method calls modify the array, which can be extremely useful in some situations. The current design gives the programmer the most options.
Why couldn't it be that, just like for a primitive data type...
The last reason is that an array is not a primitive data type - it is an object. The decision was most likely made to make arrays as consistent as possible with the way other objects in Java behave.
The answer is that all objects, in fact all method arguments are passed by value. Your assessment "Had the same been done for arrays" is wrong because the same is done for arrays. Arrays, like all object references, are passed by value. The copy of a primitive value sent to a method is the same value the caller passed. The copy of an array pointer sent to a method is the same value the caller passed. The copy of any object pointer sent to a method is the same value the caller passed.
It points to the same object, because the pointer is copied by value.
Why, you ask? Because it's simple, it's valid, and really has no downside.
Array is a container (data structure) that hold a set of objects.
Those objects could be huge or small. and the array could contain many objects
imagine with each array reference we do full copy
the language will be extremely slow and inefficient
So the main reason for this is the efficiency

Why when I pass an array, it changes value in the method? Amazing [duplicate]

This question already has answers here:
Changing array in method changes array outside [duplicate]
(2 answers)
Closed 3 years ago.
public class Test {
public static void main(String[] args) {
int[] arr = new int[5];
arr[0] = 1;
method(arr);
System.out.println(arr[0]);
}
private static void method(int[] array)
{
array[0] = 2;
}
}
After invoking method, arr[0] becomes 2. Why is that!?
You can call set methods on objects passed to a method. Java is pass by value, which means that you can't replace an object in a method, though you can call set methods on an object.
If Java were pass by reference, this would pass:
public class Test {
public static void main(String[] args) {
Test test = new Test();
int j = 0;
test.setToOne(j);
assert j == 1;
}
public void setToOne(int i) {
i = 1;
}
}
Java is Pass-by-Value, Dammit! http://javadude.com/articles/passbyvalue.htm
This is because Java uses Call by Object-Sharing* (for non-primitive types) when passing arguments to method.
When you pass an object -- including arrays -- you pass the object itself. A copy is not created.
If you mutate the object in one place, such as in the called method, you mutate the object everywhere! (Because an object is itself :-)
Here is the code above, annotated:
public static void main(String[] args)
{
int[] arr = new int[5]; // create an array object. let's call it JIM.
// arr evaluates to the object JIM, so sets JIM[0] = 1
arr[0] = 1;
System.out.println(arr[0]); // 1
method(arr); // fixed typo :-)
// arr still evalutes to JIM
// so this will print 2, as we "mutated" JIM in method called above
System.out.println(arr[0]); // 2
}
private static void method(int[] array)
{
// array evaluates to the object JIM, so sets JIM[0] = 2
// it is the same JIM object
array[0] = 2;
}
Happy coding.
*Primitive values always have call-by-value semantics -- that is, a copy is effectively created. Since all primitive values are immutable this does not create a conflict.
Also, as Brian Roach points out, the JVM only implements call-by-value internally: the call-by-object-sharing semantics discussed above are implemented by passing the value of the reference for a given object. As noted in the linked wikipedia article, the specific terms used to describe this behavior differ by programming community.
Additional:
Pass by value or Pass by reference in Java? -- see aioobes answer and how it relates with Brian Roachs comments. And aioobe again: Does array changes in method?
Make copy of array Java -- note this only creates a "shallow" copy.
Because that's exactly what you're telling it to do. Java passes first by value, then by reference. You're passing in the array, but any modifications you make to that array will be reflected on any other accesses to that array.
A quick example for thought:
If within method you did array = null, no change would be visible from main - as you would be changing the local value of array without modifying anything on the reference.
Because when you are passing argument like int/double/char etc. they are the primitive data types and they are call by value - meaning their values are copied to a local variable in this method (that has the same name as the names in your argument) and changes made to them are only changes made to these local var -> does not affect your primitive type variables outside the method
however an array or any object data type is called by reference -> the argument pass their address(reference) to method. that way, you still have a local variable named by them which has the reference. You can change it to reference another array or anything. but when it is referencing an array, you can use it to set the value of the array. what it does is accessing the address it is referencing and change the content of the referenced place
method(arr[0]);
I think that's supposed to be
method(arr);
But anyway the value passed as argument to the method is the reference to the array and the local variable arr in the method is referencing the same array. So, within the method you are making changes to the same array.
Java is pass by value. What confuses people is that the 'value' of a variable that refers to an object allocated on the heap is a reference, so when you pass that, you pass the reference 'by value' and therefore it refers to the same object on the heap. Which means it doesn't matter from where you modify the referent; you're modifying the same thing.

Simulating pass by reference for an array reference (i.e. a reference to a reference) in Java

I was wondering, in java, is it possible to in anyway, simulate pass by reference for an array? Yes, I know the language doesn't support it, but is there anyway I can do it. Say, for example, I want to create a method that reverses the order of all the elements in an array. (I know that this code snippet isn't the best example, as there is a better algorithms to do this, but this is a good example of the type of thing I want to do for more complex problems).
Currently, I need to make a class like this:
public static void reverse(Object[] arr) {
Object[] tmpArr = new Object[arr.length];
count = arr.length - 1;
for(Object i : arr)
tmpArr[count--] = i;
// I would like to do arr = tmpArr, but that will only make the shallow
// reference tmpArr, I would like to actually change the pointer they passed in
// Not just the values in the array, so I have to do this:
for(Object i : tmpArr)
arr[count++] = i;
return;
}
Yes, I know that I could just swap the values until I get to the middle, and it would be much more efficient, but for other, more complex purposes, is there anyway that I can manipulate the actual pointer?
Again, thank you.
is there anyway that I can manipulate the actual pointer?
Java does not pass by reference, so you can't directly manipulate the original pointer. As you've found out, Java passes everything by value. You can't pass a reference to an array object, and expect a method to modify the original reference to point to another array object.
You can, of course:
Modify elements of the referred array object (ala java.util.Arrays.sort)
Pass a reference to an object with a settable field (e.g. Throwable has a setStackTrace)
return the new reference instead (ala java.util.Arrays.copyOf)
Well, you can explicitly pass an object that contains a reference. java.util.concurrent.atomic.AtomicReference is ready out of the box, although it does come with volatile semantics that you probably don't want. Some people use single element arrays to returns values from anonymous inner classes (although that doesn't seem a great idea to me).
This method reverses the Array's elements in place. The caller sees the changes. (In Java everything is passed by value, including object references.)
public static void reverse(Object[] arr) {
for ( int i = 0, j = arr.length - 1; i < j; i++, j-- ) {
Object temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
In Java Object reference is passed by value.
So if you looking for something like
function referenceCheck()
{
int[] array = new int[]{10, 20, 30};
reassignArray(&array);
//Now array should contain 1,2,3,4,5
}
function reassignArray(int **array)
{
int *array = new int[] { 1, 2, 3, 4, 5};
}
Then its not possible in Java by any direct means.
If we need to change only the values stored in an array, then we can do it since object reference is passed by value.
You want to pass a reference to the array reference. In that case you just have to either create a class to hold the reference and pass a reference to that class or just pass a 1-element array of the type being passed. Then you'd be passing either an object holding the array or an array whose only element contains the array you want to operate on.

Categories

Resources