I am going to ask a basic question about Java memory usage.
Imagine we have an array List and it is large enough and we don't like to use more memory. Now if I want to pass this array to another methods in this class, or other classes through their constructor or method, do I need additional memory/is there additional memory usage for this array?
If yes, could I just make this array package level, and therefore the other classes in this package could access it directly, without any memory need.
Thank you in advance.
No, no additional memory is necessary. The parameter of a function is passed by copy of the reference. It means that for any kind of object only 4 additional bytes are used.
If you pass an array as parameter and you modify it in the body of the method the changes will be exported outside of method.
Instead if you reassign the array variable, the difference is not visible externally.
This happens because the parameters are passed as copy of the reference and not by reference.
public void vsibleModification(int[] a) {
for (int i = 0; i < a.length; i++) {
// This change is visible outside of method because I change
// the content of a, not the reference
a[i] = a[i] + 1;
}
}
public void nonVisibleModification(int[] a) {
// Non visible modification because a is reassigned to a new value (reference modification)
a = new int[2];
a[0] = 1;
a[1] = 2;
}
Related
For those who had read my first question, I think I found where the problem is. The problem is in the mutate method and especially in this instruction:
Chromosom ch=new Chromosom(); // Chromosom is a class who use hash table
Chromosom k= new Chromosom(); // Class chromosom extends hashmap <integer,parc>
k.initialise();
for(int i=0;i<l.size();i++) ch.put(i,k.get(i)); // in this instruction i think
And this is the constructor of Chromosom:
public Chromosom(){ // construct a blank chromosom
super();
this.identifiant = 0;
NbEquipeExterne = 0;
NbEquipeInterne = 0;
CoutMinimal = 0;
CoutMensuel = 0;
}
When I change the values of ch, the values of k change too?
How can I pass the k's values to ch by copy and not by reference?
First of all Java is always pass-by-value. or rather pass-by-copy-of-the-variable-value not pass by reference. You might be changing objects of Chromosom with k in the constructor.
No danger, both ch and k are separate objects.
Furthermore you can do
ch.putAll(k);
which is a nice short-cut to remember.
Caveat
If the values of the maps are stateful objects (having mutable fields to contain some changing info), then changing that field would change the field of the simgle value object in both tables.
BitSet bits = k.get(i);
bits.set(3);
// Now ch.get(i) being the same object, also has bit 3 set.
If a class has a static field, then that field is once per class, a single instance. So you could have in say Chromosome:
static String copyright;
Chromosome.copyright = "All rights reserved"; // Clearest style
k.copyright = "All rights given to the community";
ch.copyright = "MIT license";
And you would have dealt with the same single variable, with vaklue "MIT license".
About Java
A nice design decision was made in java:
If you pass a variable to a function/method, the object/value will be passed. It may never happen that the variable itself gets an other object/value. (Not the address of the variable is passed.) Java has pass-by-value, no pass-by-reference.
I am a little confused as to how my Java program is allocating memory. Below is a typical situation in my program. I have an object created on the Heap inside of a class which I pass to other functions inside of other classes.
public class A {
private List<Integer> list = new ArrayList<Integer>();
public A() {
for(int i = 0; i < 100; i++)
list.add(i);
}
public void foo() {
B b = new B();
b.bar(this.list);
}
}
public class B {
A a = new A();
public int bar(List<Integer> list) {
list.add(-1);
return list.size();
}
public int getSize() {
List<Integer> list = a.list;
return a.size();
}
}
My question(s) are about how the memory is used. When A's list gets passed to B.bar(), does the memory get copied? Java is pass-by-value so I assumed the B.bar() function now contains a copy of the list which is also allocated on the heap? Or does it duplicate the list and put it on the stack? Or is the list duplicated at all? Similarly what applies to these memory questions inside of B.getSize()?
It's probably clearer to say that in Java, object references are passed by value.
So B gets a copy of the reference (which is a value) to the List, but not a copy of the List itself.
You can easily prove this to yourself by getting B to modify the List (by adding or removing something), and observing that A's List also changes (i.e. it is the same List).
However, if you change B's reference to the List (by creating and assigning a new List to it), A's reference is unchanged.
Java is pass-by-value, but the value of an expression or variable is always either a primitive or a reference. A reference, in turn, is either null or a pointer to some object.
In your case: private List<Integer> list = new ArrayList<Integer>(); declares list as having a reference type, and makes its value a pointer to a newly allocated ArrayList object.
When you use list as an actual argument, for example on the b.bar(this.list); call, the formal argument list in b.bar is initialized with a copy of that pointer. That is, bar's formal argument points to the same ArrayList object as A created. The ArrayList object is not copied.
Java is pass-by-value, dammit!
However, you only ever have access to references to Objects. In that sense, you are passing Object references by value.
I've written a function which. Problem is, the parameters I'm sending, is being manipulated in the main program, though it is not my intention. I just want to have the value inside the function, but while operating, the actual value in the main program is also being changed.
How can I prevent this?
Here is my code:
Tiles[][] MoveRight(Tiles[][] tilesArray) {
Tiles[][] tempTilesArray = new Tiles[3][3];
Tiles[][] tempTilesArrayToSend = new Tiles[3][3];
tempTilesArrayToSend = CopyTilesArrays(tilesArray, tempTilesArrayToSend);
ArrayIndex zeroPos = FindZero(tilesArray);
Tiles zeroTile = GetTile(zeroPos, tilesArray);
if (zeroPos.column != 2) {
ArrayIndex otherPos = new ArrayIndex(zeroPos.row,
zeroPos.column + 1);
tempTilesArray = SwapTilesPositions(zeroTile, GetTile(otherPos,
tilesArray), tempTilesArrayToSend);
}
return tempTilesArray;
}
The array I'm sending inside the SwapPositionFunction is actually modifying the tilesArray itself. Though I've made a new instance of tiles array and then sent it.
Without seeing what is done in
CopyTilesArrays (tilesArray, tempTilesArrayToSend);
we can not say much.
Note, that in Java, there is no pass-by-value or pass-by-reference, but a copy of the reference is passed to the methods. This copy of a reference will - in case of objects and Arrays - point to the same, original object, so if you change the underlying/embedded object, the original object is affected, but if you change the reference, the original object is not affected.
IF you want to pass an independent copy of your array, you have to perform a deep ocpy. Maybe that is, what CopyTilesArrays is supposed to do, but without seeing it, we don't know.
Note too, that there are, or better: that there can be several layers of objects, with different reasons to stay on the surface, to go to the core, or to stay somewhere in between.
For example, to make a deep copy from the Array of Array of Tiles, you could do something like this:
public class TilesCopy {
Tiles[][] copyTilesArrays (Tiles[][] from, int outer, int inner) {
Tiles[][] to = new Tiles[outer][inner];
int o = 0;
for (Tiles [] tiles: from) {
Tiles[] fresh = new Tiles [inner];
int i = 0;
for (Tiles t : tiles)
{
fresh[i] = t.deepCopy ();
i++;
}
to [o] = fresh;
o++;
}
return to;
}
}
Note, that in the innermost loop, the elements aren't just referenced with fresh[i] = t;, but with a deep copy, to keep the objects in the original Array unaffected.
You could copy an array of arrays of Tiles in multiple other ways. For example, you could rearrange the outer array. If the Tiles were
[[A][B][C]]
[[D][E][F]]
[[G][H][I]]
you could copy them, and modify the target to be:
[[G][H][I]]
[[D][E][F]]
[[A][B][C]]
with just copying the outer arrays, and rearranging them. And you could copy the inner arrays, to be:
[[C][B][A]]
[[F][E][D]]
[[I][H][G]]
If you now modify the A to a, the original A will be affected too, without a deep copy:
[[C][B][a]]
[[F][E][D]]
[[I][H][G]]
[[a][B][C]]
[[D][E][F]]
[[G][H][I]]
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.
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.