Soronume
Soronume

Reputation: 145

Java: for / forEach run through int matrix

This is not a 'how to do sth.' question, but a 'why can't I do it that way' question.

Obviously I have missed something important here (sth. about references I guess) to understand this problem and it would be nice if someone could explain it to me.

I did find the other posts where this question was dealt with before, but none of them explained it.

I want to assign new values to every element of an int matrix.

I have a piece of code like this:

public static void main(String[] args)
{
    int[][] tileMatrix = new int[5][5];

    System.out.println("New Tile Values:");
    for ( int[] tileLine : tileMatrix)
    {
        for ( int tile : tileLine)
        {
            tile = (int) (Math.random() * 39);
            System.out.print(tile + "  ");
        }
        System.out.println("");
    }

    System.out.println("Check Values");
    for ( int[] tileLine : tileMatrix)
    {
        for ( int tile : tileLine)
        {
            System.out.print(tile + "  ");
        }
        System.out.println("");
    }
}

That leads to that:

New Tile Values: 22 17 29 20 5
12 13 38 35 19
1 9 10 23 27
24 3 36 3 19
37 4 5 18 26
Check Values 0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

So obviously I can't change the values like that. I can't find out whether that is generaly impossible in foreach loops, or whether I'm just doing it wrong. I could fix my problem with a normal for loop, I know that, but why do I have to?

Upvotes: 0

Views: 654

Answers (3)

Richard Tingle
Richard Tingle

Reputation: 17226

= only affects the variable you are currently interacting with

A very simple example shows why your loop doesn't change the values stored in the array

int a=5;
int b=a;
b=10;
System.out.println(a); //prints 5

Your code is obviously more complex than this, but it is the same at heart. Each value from the array is copied into a variable and then that variable is manipulated.

for ( int[] tileLine : tileMatrix)
{
    for ( int tile : tileLine)
    {
        tile = (int) (Math.random() * 39); //<---tile is the same as b in my example
        System.out.print(tile + "  ");
    }
    System.out.println("");
}

Variables that refer to objects hold memory addresses

You asked why the following does affect the underlying 2D array

for ( int[] tileLine : tileMatrix){
    for (int i=0;i<tileLine.length;i++){
        tileLine[i] = (int) (Math.random() * 39);
    }
}

This is because tileMatrix does not contain 1D arrays in each of its elements, it contains memory addresses (huge oversimplification). I'm going to refer to memory addresses as #120 for the 120th region of memory.

for ( int[] tileLine : tileMatrix){
    //tileLine is a memory address, perhaps #130, it is not an int[] itself
    //we only take a copy of the memory address, not a copy of the array itself 

    for (int i=0;i<tileLine.length;i++){
           //tileLine points to the piece of memory within the original 
           //array

           //tileLine[i] actually means get the array at memory address `#120` 
           //and put `(int) (Math.random() * 39);` in its i-th entry
           tileLine[i] = (int) (Math.random() * 39);
    }
}

So to conclude when you use a variable java (behind the scenes) deferences it and gets the real object for you to work with.

tileMatrix is actually 1D matrix (pretending to be a 2D matrix). It may contain the following

#120
#130
#1180
#2021
#2022

Then when we look at one of those memory addresses, say #120, we find it contains the following

1
5
5
1
4

So you see if we have the memory address #120 it doesn't matter where we are, we're refering to the same place.

the memory model here is not supposed to be accurate, only conseptually useful, its more complicated than this in reality

Upvotes: 0

larryboymi
larryboymi

Reputation: 696

I know you mentioned you didn't want to know how to do something, but you might want to look at the JDK8 Arrays parallelPrefix method

Upvotes: 0

Luiggi Mendoza
Luiggi Mendoza

Reputation: 85779

Enhanced for loop will only take the values of the elements in the array and store them inside variables. With values, this mean a copy of the primitive or a copy of the reference value stored in the array. If you reassign a new value to this variable, you're just modifying the value of this variable, not the value in the array.

This explain why this for loop doesn't work:

for ( int tile : tileLine) {
    tile = (int) (Math.random() * 39);
    System.out.print(tile + "  ");
}

The for statement above behaves like this:

for (int i = 0; i < tileLine.length; i++) {
    int tile = tileLine[i];
    //you modify the local variable tile, not the element in the array
    tile = (int) (Math.random() * 39);
    System.out.print(tile + "  ");
}

If you want to modify the values in the array, you should modify the value directly in the array:

for (int i = 0; i < tileLine.length; i++) {
    tileLine[i] = (int) (Math.random() * 39);
    System.out.print(tileLine[i] + "  ");
}

Upvotes: 8

Related Questions