3

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?

Smiled_One
  • 445
  • 1
  • 4
  • 17
  • 4
    The value of an array is a reference (like every other *`Object`*). – Elliott Frisch Jan 16 '16 at 22:08
  • 1
    Why would you not see 2 queens, since there is nothing in this code which removes the queen from its first cell ? – Valentin Waeselynck Jan 16 '16 at 22:11
  • What are the two int arguments in the constructor of Cell? Are you passing an initial location? What is in the body of printBoard()? Does it probe the pieces to see where they are located or does it rely on the contents of the boardGame array? – Jim W Jan 16 '16 at 22:28
  • @Jim W, the body of the printing relay on the contents of the boardGame array. The location inside the cells used for other function who didn't always know where the specific cell came from. – Smiled_One Jan 17 '16 at 07:38

3 Answers3

5

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);
M.P. Korstanje
  • 10,426
  • 3
  • 36
  • 58
4

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.

J Fabian Meier
  • 33,516
  • 10
  • 64
  • 142
  • A copy of the reference is passed. You can't modify the referenced object, even if it isn't declared final, because it's just a copy of the reference and the original reference, referencing the same object, will stay unaffected, while the referenced object might be mutable. – user unknown Jan 16 '16 at 22:30
2

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.

Stack and Heap memory space

Array Allocation

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
Community
  • 1
  • 1
Aditya Guru
  • 646
  • 2
  • 10
  • 18
  • Thanks, I edit the question. – Smiled_One Jan 17 '16 at 23:17
  • @Smiled_One I'm afraid, I did not understand the Q asked in the edit. It might help if you could use some examples of what you understand – Aditya Guru Jan 18 '16 at 03:43
  • I'm sorry my English is not so good, but I add an example. Thank you for the help – Smiled_One Jan 18 '16 at 19:00
  • 1
    Okay, I got your question but my suggestion is try out according to my above explanation before reading further.. – Aditya Guru Jan 20 '16 at 10:33
  • 1
    Similar phenomenon as above happens there too. In outsideTest() you pass an object reference value of board... equivalent to e1 in diagram above so it has access to changing the object and the properties..In the diagram a copy of e1 can be used to change name, ssn, yearOfBirth for e1. where as for test() you pass the int value so access to a copy of the int value num only so cannot change num. – Aditya Guru Jan 20 '16 at 10:40
  • I thing I'm starting to understand it. And I am able to change class values from function inside the class because the function go the class pointer and change it value. That's why it got change inside the class...it's not a local value. – Smiled_One Jan 22 '16 at 09:48
  • 1
    Yup... I guess you got it. When the parameter is of reference(pointer or address though java geeks like to call references) type like board or boardGame your function has a **copy of that reference(address)** so, it can go to the location pointed to by it and changes would be globally visible. If you pass a primitive datatype(int) you get **copy of the data** in the location(its not a reference to anywhere). So, the changes made are only on the copy and lost with the function Keeping in mind the above, it's just a matter of being able to know what type is passed -- reference or primitive – Aditya Guru Jan 22 '16 at 10:37