This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 7 years ago.
I have a list of Cell object that represent a board game inside the board class.
Cell boardGame[][] = new Cell[8][8];
I needed a temporary cell to try the player move on him and compare it to the other cells, so I though that I could use a java pass-by-value to do it.
test(board.boardGame);
board.printBoard();
private static void test(Cell[][] boardGame) {
Cell c = new Cell((new Soldier(ChessPiece.QUEEN, Color.WHITE)), 7, 4);
boardGame[7][7] = c;
}
I read some post about java here, but apparently I still didn't catch it 100%.
I expected to see only one white queen on the board, but I saw two.
I know that if you pass a reference you can change its values, but I though that if I would pass the array itself its members won't be modified unless I would execute a return.
Please help me to understand this subject better.
Thanks
Edit:
I think I don't understand when it called attributes and where it doesn't.
I though the different it if you are call "new" or not.
When its part of another object it called attribute right? but every object can be created as part of another object. I can create a new string in dog class and then create the dog class in the animal class and then create it in another class. So only the top class is in the stack?
For exemple:
public class Board { //fake class
int num= 0;
public void test(int i){
i = 1;
}
}
and on another class:
public class Main {
static void outsideTest(Board board){
board.num = 1;
}
public static void main(String[] args) {
Board board = new Board();
System.out.println(board.num);
board.test(board.num);
System.out.println(board.num);
outsideTest(board);
System.out.println(board.num);
}
}
Now I didn't understand why on test() method the num didn't change and on outsideTest() the num change, num as been created in the heap because its part of the board object, so its need to be changed on both cases no?
The best and least confusing way to remember it is as follows: Java passes everything by value, that includes the references. :)
When you have a variable:
Object a = new Object();
you don't actually have an object stored in a. What you have is a reference to an object somewhere in memory.
Likewise when you call a method on an object:
String b = a.toString();
you don't do that. What you call is a method that uses the data of the referenced object as its context.
So when you pass an object as an argument
System.out.println(b);
You don't pass the whole object. You pass the reference and that reference is passed by value.
edit:
If the reference were not passed by value, but by reference, you could do something like this, which fortunately you can't.
public void swap(Object a, Object b){
Object swap = a; a = b ; b = swap;
}
String a = "a";
String b = "b";
swap(a,b);
// would print "b a" if references were
// passed by reference but instead prints
// "a b" as they're passed by value.
System.out.println(a + " " b);
The reference to the object is passed by value, which means that
boardGame = new Cell[8][8];
does not do any harm, but changing anything you get from boardGame does.
Java is essentially always "pass-by-value".
Caveat: It passes the value stored in the memory for the variable.
For primitive data types, the memory is allocated in stack space, whereas for objects reference memory is allocated in stack space but the object itself is created in heap. Similar can be stated for arrays too though they are not exactly objects in a strong sense.
Diagrams below would make it clearer.
Your Cell object 2D array should seem something like anObjectArrayVar (not exactly as the ref in the diagram pointing to the objects should now be pointing to the rows and we would need another level of allocation in heap in between ref and objects for each row (a set of cells refering to the objects).
So, when you pass boardGame, the value stored in the stack is passed that stores the reference to the array of objects (just like the value stored in the anObjectArrayVar). If say the list of refs is stored in location numbered 50 then anObjectArrayVar would have stored that and it passes that value to the test method when we call it. In such a scenario the test method wont be able to goto memory location anObjectArrayVar and change its value (to say 100) as it has only a copy of the value but it could easily change what it refers to(directly or indirectly) like the values in ref or the next level (and add new objects as in your case adding a new cell with queen) or the objects pointed to by them and those changes would reflect through out the program!
I would also like to draw your attention to the fact that the code
boardGame[7][7] = c;
would replace the current cell (as well as the soldier currently in it) which would create major issues if there was originally a soldier in that place at that point in the game. The game state would actually change.
As a suggestion (given the limited knowledge about your design) I would say at least save the cell in some other value in test method before replacing it.
Cell old = boardGame[7][7];
//now do all your operations
boardGame[7][7] = old;//just before returning from the function
Related
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 3 years ago.
I know a little bit about how Java is pass by value, and how passing a object to a method can change the object's field (ex. change1() in the Car class).
However, my question is why change2() and change3() don't change anything (especially change3())
public class question {
public static void main(String[] args)
{
Car c1 = new Car(1000,"Hyundai");
Car c2 = new Car(2000,"BMW");
c1.change3(c1);
c1.change3(c2);
System.out.println(c1.name + " "+ c1.price );
System.out.println(c2.name + " " + c2.price);
}
}
class Car
{
int price;
String name;
Car(int p , String n)
{
this.price=p;
this.name=n;
}
void change1(Car c)
{
c.price=0;
c.name="Changed";
}
void change2(Car c)
{
c = new Car(999,"Honda");
}
void change3(Car c)
{
c = new Car(888,"Audi");
c.price=80;
c.name="xxx";
}
}
Every time JVM executes new operator, a new Object/Instance is being created. You are creating a new object of the Car type in your change3(Car c) method and storing the reference on that object into local variable c. After this, anything you set on that c is amending new object, and not the one you passed a reference of.
void change3(Car c) //receives the reference to the object you pass;
{
c = new Car(888,"Audi"); //creates a new Car object and assigns reference to that **new object** to the variable c.
c.price=80; //here, you're changing the price/name fields of different object.
c.name="xxx";
}
Pay attention, that in change1(Car c) you do not create a new object, but in change2(Car c) and change3(Car c) - you do [explicitly] create new objects.
Edited:
Java is pass by value for primitives and for objects, it's a copy of the original reference.
To be more specific it's a copy of the same reference, which means that is a different pointer to the same reference of the same object, so if you change the object in your method, the original object is going to change too. BUT if you assign it again (with the new operator in your case) , you are going to update your pointer inside your method to a new reference, but the original pointer remains as it was.
Another about probably most upvoted question about Java on StackOverflow :)
The pass by value or reference probably comes from the understanding and conventions used in C++ language.
The types of parameters are passed by value.
But when passing an object it doesn't pass the whole object, but a copy of address in memory (aka reference) pointing to that object.
Passing parameter by reference means it's possible to change that parameter inside of an method and that change would be visible outside of that method.
Java in "passed by value" because changing/reassigning the passed parameter isn't visible outside of an method.
In the case of:
void change1(Car c)
{
c.price=0;
c.name="Changed";
}
The assignments to price and name are visible outside of that method, because the the method changes the member fields of the passed instance and not the instance itself.
The change2 and change3 methods doesn't reflect outside of them because of reassigning the passed c parameter.
When reassigning passed object, the address behind passed object parameter no longer points to the same object as originally passed one.
Similary, it's not possible to reflect the change or reassigning of passed primitive or:
void change4(String name) {
name = "whoopsie";
}
//and later calling it with:
c1.change4(c1.name);
Changing the inner state of an object isn't the same as changing the object itself.
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.
I'm working on an assignment right now, and am confused by this. The code given is simple:
public class Variables{
public static void main(String[ ] args){
StringBuffer b = "ghi";
f(b);
System.out.println(b):
}
public static void f(StringBuffer p){
p.concat("jkl");
}
}
The question simply asks what the output of the print statement will be. My first thought was simply "ghi", but this was incorrect. If the method f is taking b as a parameter and setting it to p, then how does .concat() modify b? I've read through the StringBuffer documentation and dont understand why this wouldn't end up with b equaling "ghi" while p is "ghijkl".
Basically, how is the .concat() method called on p also modifying b?
First, you need to create a StringBuffer correctly.
StringBuffer foo = new StringBuffer("some string");
You passed an object to a function. Java passes objects as references (the references themselves of course are passed by value). See: Is Java "pass-by-reference" or "pass-by-value"?
Since you have a reference to a StringBuffer and not a copy of it, you are actually modifying the same object as you would as if you were in main.
This is the difference between parsing by reference and parsing by value.
When you create a method taking a primitive, for example, it undergoes what is called parsing by value. The JVM pretty much creates a copy of the value and that is what you get in the method.
int j = 0;
foo(k);
System.out.println(j); //Will still be 0.
public static void foo(int i) {
//i is not j (what you called the method with), it is a copy of it that is only valid within this method
i++;
}
Now when you call the method with an object such as a StringBuffer you are parsing by reference. This means that you are not parsing the value of the StringBuffer(not parsing a StringBuffer` with "ghi" as its contents), but you are rather parsing a pointer to it. Using this pointer you can still operate on the original object within other methods and bodies of code.
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
public class StackOverFlow {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("A");
al.add("B");
markAsNull(al);
System.out.println("ArrayList elements are "+al);
String str = "Hello";
markStringAsNull(str);
System.out.println("str "+ str);
}
private static void markAsNull(ArrayList<String> str){
str.add("C");
str= null;
}
private static void markStringAsNull(String str){
str = str + "Append me";
str = null;
}
}
This outputs:
ArrayList elements are [A, B, C]
str Hello
In the case of ArrayList, the added elements are getting retrieved.
In case of String the method call has no effect on the String being passed. What exactly is the JVM doing? Can anyone explain in detail?
In the case of Arraylist string objects the added elements are getting retrived. In case of String the method call has no effect on the String being passed.
It happens cause Java is Pass-by-Value and Strings are immutable
When you call
markAsNull(ArrayList<String> str)
The a new reference by name str is created for the same ArrayList pointed by al. When you add an element on str it gets added to same object. Later you put str to null but the object has the new values added and is pointed by a1.
When you call
markStringAsNull(String str)
{
str = str + "Append me";
// ...
}
The line str = str + "Append me"; creates a new String object by appending the given string and assignes it to str. but again it is just reference to actual string which now pointing to newly created string. (due to immutablity) and the original string is not changed.
The markXAsNull methods are setting the local references to be null. This has no effect on the actual value stored at that location. The main method still has its own references to the values, and can call println using those.
Also, when doing the string concatenation, toString() is being called on the Object, and that is why the ArrayList is outputted as a list of its values in brackets.
From the Book: SCJP - Sun Certified Programmer for Java 6 Study Guide (Katty Sierra - Bert Bates) Chapter 3 Objective 7.3 - Passing Variables Into Methods
Java is actually pass-by-value for all variables running within a single
VM. Pass-by-value means pass-by-variable-value. And that means, pass-by-copy-ofthe-
variable!
The bottom line on pass-by-value: the called method can't change the caller's
variable, although for object reference variables, the called method can change the
object the variable referred to. What's the difference between changing the variable
and changing the object? For object references, it means the called method can't
reassign the caller's original reference variable and make it refer to a different object,
or null. For example, in the following code fragment,
void bar() {
Foo f = new Foo();
doStuff(f);
}
void doStuff(Foo g) {
g.setName("Boo");
g = new Foo();
}
reassigning g does not reassign f! At the end of the bar() method, two Foo objects
have been created, one referenced by the local variable f and one referenced by
the local (argument) variable g. Because the doStuff() method has a copy of the
reference variable, it has a way to get to the original Foo object, for instance to call
the setName() method. But, the doStuff() method does not have a way to get to
the f reference variable. So doStuff() can change values within the object f refers
to, but doStuff() can't change the actual contents (bit pattern) of f. In other
words, doStuff() can change the state of the object that f refers to, but it can't
make f refer to a different object!
Java follows passby value concept ( there is no pass by reference in java ) . So when you pass a string to the function it sends a "copy of reference" to that string to the function. So even if you set the variable to null in the function, when it returns to the caller it refers its original value only. That's why original string has no effect.
In case of Arraylist, copy of reference refers to the original Arraylist (which is also the same in case of string). But when you add something into ArrayList, it refers to the original object and so that you can see the effect. ( try in method arraylist=new ArrayList(), your original arraylist will remain as it is).
In case of string, when you do
str=str + "abc";
Java creates a new String object which will have reference to string "xyzabc" ( e.g. str="xyz") and "xyz" will be eligible for the garbage collection. But as "xyz" is still having an variable which refers to it it ( original string) will not be garbage collected. But as soon as the function call gets over "xyzabc" goes for garbage collection.
Summary of the discussion is, as long as an reference refers to the same object you can make changes in the function, but when you try to change the reference ( str=str+"abc") you are refering to the new object in the method so that your original object will remain as it is.
In Java, you may create one object, and referenced by multiple pointers. Calling a mutator method on any pointer will effectively modify the sole object, thus updating all other references.
But if you call variable assignment statements on a reference, only that pointer will be changed, since it doesn't do any object side work (this is the best I could explain...).
Passing an object to a parameter will effectively copy the reference, resulting in a single object, with two pointers - one global, and the other local.
One more point, since String is immutable, you'll actually get a new object, that is distinct from the original (from the fact that you have to say a = a + "a"), that's why it won't modify the original string.
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.