I have two questions:
First:
I have a function which returns a HashMap. To read the returned value, I write it like this:
HashMap<Integer,String> hs=my_func2();
I do the same if the function returns a HashSet.
HashSet<Integer> hs=my_func();
I wanted to know if in this way the returned value is copied into hs, or I should write a deep copy for it or I should write it like this:
HashSet hs=new HashSet(my_func());
HashMap hm=new HashMap(my_func2());
Second quesion:
I make a matrix by calling make_matrix_funciton. matrix woule be a 2-dimensional array containing:
[0 1 1
0 0 0
0 0 0]
Then I give this matrix to sort_vec, and in this function the elements of matrix change. I think java is not pointer based, so when I come out of sort_vec, matrix should be as it had been. But, it has changed! It is
[0 0 0
0 0 0
1 1 0]
which shows the changes that had been applied to it inside the sort_vec function. Is it normal and if yes, what should I do to prevent it. The code below is compilable.
public static void main(String args[]) {
int matrix[][]=new int[3][3];
matrix=make_matrix("011000000");
int indexes[]={2,1,0};
int[][] mat=sort_vec(3,matrix,indexes);
}
private static int[][] sort_vec(int motifsize,int [][]mat,int[] indexes)
{
int[] main_index={0,1,2};
int l=indexes.length;
for (Integer i=0;i<l;i++)
if(indexes[i]!=main_index[i])
{
int j=indexes[i];
int k=main_index[i+1];
for(;k<l;k++)
if(indexes[k]==main_index[i])
break;
indexes[k]=j;
mat=exchange(motifsize,mat,j,main_index[i]);
}
return mat;
}
private static int[][] exchange(int motifsize,int [][]matrix,int x,int y)
{
int temp;
for(int i=0;i<motifsize;i++)
{
temp=matrix[i][x];
matrix[i][x]=matrix[i][y];
matrix[i][y]=temp;
}
for(int i=0;i<motifsize;i++)
{
temp=matrix[x][i];
matrix[x][i]=matrix[y][i];
matrix[y][i]=temp;
}
return matrix;
}
private static int[][] make_matrix(String id)
{
int matrix[][]=new int[3][3];
int c=0;
for(int x=0;x<3;x++)
for(int y=0;y<3;y++)
{
if(id.charAt(c)=='1' || id.charAt(c)=='5')
matrix[x][y]=1;
c++;
}
return matrix;
}
Java always passes Objects by reference, so if you return a HashMap-Object from a function, the reference will be passed to the hs variable in your example. Passing the HashSet to the constructor of a new HashSet instance will not work. It will create a new HashSet with the same object references as in the original one. If you modify one of these objects, the change will appear on all other reference points, too.
If you want to totally detach the copy, you will need your own method for deep copying because in the JavaDoc for the clone() method it says:
Returns a shallow copy of this HashSet instance: the elements themselves are not cloned.
The same goes for arrays. Every array is an object, so if you modify an element, it will be modified for all references to this array. To create a deferred copy, use System.arrayCopy
You are misunderstanding how Java's references work.
In the first part, your object will be a reference to a HashMap - i.e., whatever object you've returned from the function
In the second part, you are passing a reference to an int[][], it is not pass by value when it's an array of primitives. Thus, your function will modify the array. If you want a function that does not modify the input array, you need to copy what is passed in to the function or you will need to copy the array before you pass it to your function.
The behavior in Java sorting routines is that they modify the original array.
In sum, there is no way to 'pass by value' an object or array in Java. If you want this behavior, you have to clone (e.g., copy) the object manually or using #user3001's suggestion
Once you figure this out, you may want to read this as well: http://javadude.com/articles/passbyvalue.htm
Related
This question already has answers here:
How do I do a deep copy of a 2d array in Java?
(7 answers)
Closed 4 years ago.
I'm relatively new to Java, and I just learned this
import java.util.Arrays;
public class Foo {
private int[][] foo;
public Foo(int[][] arr) {
this.foo = arr;
}
#Override
public String toString() {
return Arrays.deepToString(this.foo).replace("],", "],\n");
}
public static void main(String[] args) {
int[][] p = { { 0, 0 }, { 0, 0 } };
Foo g = new Foo(p.clone()); // doesn't work with p nor p.clone()
System.out.println(g);
p[0][0] = 1;
System.out.println(g);
}
}
Here I create an object with a reference to another object, and I can alter the object from the outside since I have the reference to the thing I just passed as an argument to the constructor.
This, although I understand why it happens, seems counterintuitive to me. If I save something as an attribute of an object I expect the object to have a “private” copy not accessible outside.
And I tried with .clone() and doesn't solve it. So the question is...
How is this usually done? Do I need to write a few for loops inside the constructor to get every value out of the argument?
(Or is this a non-issue?)
This last part of the question is important, may be this is a non-issue. Or do people do “something” (a few loops to get a deep clone)?
The problem here is that java doesn't really have 2-D arrays. This:
int[][] x;
is an array of int arrays. It is not a 2D int array, though of course an array of int arrays does feel a lot like a 2D array. For most intents and purposes it iS a 2D int array, unless it isn't, and with clone, it isn't. The clone() impl of an array makes a new array and just copies each and every value, verbatim, into the new array. Which means that your array of int arrays is cloned, but the inner int arrays are not.
When treating int[][] as 'this is a 2D array', yeah, that is unintuitive. When treating int[][] as 'an array of int arrays', it is quite intuitive. You wouldn't expect an array of arraylists, when cloned, to also clone each individual arraylist either.
Soo.. how do you deep-clone an array of arrays (of arrays of arrays)? See How do I do a deep copy of a 2d array in Java? for lots of options :)
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
}
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
So I'm trying to return the contents of an array in a method.
Lets assume this array is called x and it already has values in it.
public int[] returnArray()
{
return x;
}
Now, I know that this will return the memory address of the array. So I tried this workaround I saw earlier:
public int[] returnArray()
{
int[] y=new int[x.length]
for (int i=0;i<x.length;i++)
{
y[i]=x[i]
}
return y;
}
Now, this is also returning the memory address of the array. Is there no workaround for this?
return x; returns a reference to the array, which gives you access to all the elements of the array.
You probably think you got the "memory address of the array" because you tried to print the array with System.out.println(returnArray());, which doesn't display the elements of the array. You should print the array with System.out.println(Arrays.toString(returnArray()));
You can't return anything but the address because what you can return is only one value. An array often contains more than one value.
You could return the value at position 0 of the array for example, but not all the different values at once.
And whoever posted that "workaround" obviously has no clue. This creates another array and copies the content from the original array into the new array, then returns that array's address.
However, you don't need to return the elements of an array, the array reference allows you to access the elements.
returnArray()[0] gets the first element of the returned array (reference).
To print the elements, you can iterate over the array:
for (int x : returnArray()) {
System.out.println(x);
}
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.