1

I am trying to initialize the objects inside a java array of Integers using a for loop, but the array element is null after the for loop exits.

public static void main(String[] args) {
    Integer[] x = new Integer[1];
    for (Integer xx : x) {
        xx = new Integer(1);
        System.out.println("inside for loop "+xx.toString());
    }
    System.out.println("why isn't this 1?  " + x[0]);

    x[0] = new Integer(2);
    for (Integer xx : x) {
        System.out.println("Not it's okay: " + xx.toString());
    }
}

But the array element is null after the for loop exits. Here is the output:

inside for loop 1
why isn't this 1?  null
Not it's okay: 2

Why doesn't this for loop behave the same as for (i=0;i<1;i++){x[i]=1;} ?

BrianS
  • 21
  • 6
  • 1
    I think this is a question about the for java each loop not pass by value vs pass by reference. – Ken Jun 16 '17 at 08:58

4 Answers4

6

For exactly the same reason that this doesn't work:

Integer a1 = null;
Integer a2 = a1;
a2 = new Integer(1);
System.out.println(a1.toString()); // Fails, a1 is still null

The xx in your loop is not some kind of reference to the array element; instead, it's a variable that contains a copy of the value of the array element (which is null in your case). Setting the value of xx just sets its value, it has no effect whatsoever on the array entry.

Let's follow your code through:

Integer[] x = new Integer[1];

In memory, we now have something like this (ignoring some details):

                 +−−−−−−−−−−−+
x[Ref22135]−−−−−>| Integer[] |
                 +−−−−−−−−−−−+
                 | length: 1 |
                 | 0: null   |
                 +−−−−−−−−−−−+

(That "Ref22135" inside x is a value called an object reference, telling the JVM where the array is in memory. Object references are values, like primitives are. The fact we're dealing with objects is actually irrelevant to why setting xx doesn't affect x[0], but since you're using Integer[], I have to mention it.)

Now, we enter your loop:

for (Integer xx : x) {

At this point, again ignoring some details, we have:

                 +−−−−−−−−−−−+
x[Ref22135]−−−−−>| Integer[] |
                 +−−−−−−−−−−−+
                 | length: 1 |
                 | 0: null   |
                 +−−−−−−−−−−−+

xx[null]

The value of x[0] (null) has been copied to xx.

Now we do your assignment:

    xx = new Integer(1);

Which gives us:

                 +−−−−−−−−−−−+
x[Ref22135]−−−−−>| Integer[] |
                 +−−−−−−−−−−−+
                 | length: 1 |
                 | 0: null   |
                 +−−−−−−−−−−−+

                 +−−−−−−−−−−−−−+
xx[Ref99845]−−−−>|   Integer   |
                 +−−−−−−−−−−−−−+
                 | rawValue: 1 |
                 +−−−−−−−−−−−−−+

As you can see, setting the value that's in xx ("Ref99845", a reference to the new Integer object) has no effect whatsoever on the array.

Note that this has nothing to do with the fact we're dealing with objects, it would be exactly the same if we were dealing with primitives:

int[] array = new int[1];
for (int entry : array)
{
    entry = 42;
    System.out.println(entry);
}
System.out.println(array[0]);

Output:

42
0

If we stop that code at this point:

int[] array = new int[1];
for (int entry : array)
{
    entry = 42;

What we have in memory looks something like:

                     +−−−−−−−−−−−+
array[Ref56418]−−−−−>| int[]     |
                     +−−−−−−−−−−−+
                     | length: 1 |
                     | 0: 0      |
                     +−−−−−−−−−−−+

entry[42]

The only difference when we use Integer[] is that the value being copied from x[0] to xx is an object reference rather than an int. But it doesn't matter; it's still a value, and values are always copied when assigned from one thing to another. (Copying an object reference just copies the reference, of course, not the object it refers to).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I should have shown how the enhanced `for` loop is treated by the JVM; see [Flown's answer](https://stackoverflow.com/a/44585217/157247) for that, it helps explain what's going on. – T.J. Crowder Jun 16 '17 at 09:10
1

The reason why you cannot change elements in an array by using an enhanced for loop is how these are desugared (JLS 14.14.2):

for(int i = 0; i < x.length; i++) {
  Integer xx = x[i];
  // you're working with a variable not with the i-th element
}
// is equivalent to:
for(Integer xx : x) {
  //...
}
Flown
  • 11,480
  • 3
  • 45
  • 62
  • Showing this is really useful. (You might mention you're leaving out some unnecessary details.) Small note: *"you're working with another object not with the i-th element"* Not an object, a variable. – T.J. Crowder Jun 16 '17 at 09:09
  • Thank you for the JLS reference. – BrianS Jun 16 '17 at 15:14
1

The main problem in your example is usage of the foreach-loop which does not work as you are expecting:

Integer[] ints = new Integer[5];
for (Integer a : ints) { // assign each element of the array into the temp variable "a"
    a = new Integer(1);
}

This is the same as:

Integer[] ints = new Integer[5];
for (int i = 0; < ints.length; i++) {
    // reference "a" is pointing on the same place as reference stored in ints[i]
    // which is null, so both are pointing on null address
    Integer a = ints[i]; 
    // reference "a" is now pointing on newly allocated address with Integer(1)
    // but ints[i] is still null
    a = new Integer(1);  

    System.out.println(int[i]); // prints null
    System.out.println(a);      // prints 1
}

If you would like to change the array content, you have to assign values into the array directly:

for (int i = 0; < ints.length; i++) {
    ints[i] = new Integer(1);   
}

But this is not possible with for-each loop, which always copies array[i] into the local variable.

matoni
  • 2,479
  • 21
  • 39
0

You are not adding values to the array. Hope this will work for you,

    Integer[] x = new Integer[1];
    for(int i = 0 ; i<x.length ; i++){
        x[i] = new Integer(1);
        System.out.println("inside for loop "+x[i].toString());
    }
    System.out.println("why isn't this 1?  " + x[0]);

    x[0] = new Integer(2);
    for (Integer xx : x) {
        System.out.println("Not it's okay: " + xx.toString());
    }

output

inside for loop 1
why isn't this 1?  1
Not it's okay: 2
AnjuT
  • 166
  • 1
  • 4
  • 17
  • Thanks. I realize that this works. My question is more about why doesn't the version that I posted behave the same as your code. – BrianS Jun 16 '17 at 09:04