Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Does Java Know How to Iterate an Array

String[] strs = new String[] { "1", "2", ... , "6" };

for (String s : strs) {
    System.out.println(s);
}

This is a question about java internals.

In the above code sample, how does the foreach loop figure out how long the array is? Are arrays actually objects internally or is it using stuff like sizeof that is inaccessible to front end programmers?

I have a feeling I'm just missing something stupid, but I figure it could also be cool. :-)

like image 834
SapphireSun Avatar asked Dec 30 '10 05:12

SapphireSun


2 Answers

I compiled the following code:

public class ArrayIterator
{
    public static void main(String[] argv)
    {
        String[] strs = new String[] { "1", "2", "3", "4", "5" };
        enhancedPrint(strs);
        normalPrint(strs);
    }

    public static void enhancedPrint( String[] strs )
    {
        for (String s : strs)
        {
            System.out.println(s);
        }
    }

    public static void normalPrint( String[] strs )
    {
        String[] localArray = strs;
        int len = localArray.length;
        for (int i = 0; i < len; i++)
        {
            String s = localArray[i];
            System.out.println(s);
        }
    }
} 

This is the disassembled (javap -c ArrayIterator) bytecode for the iterating functions:

The enhanced print:

public static void enhancedPrint(java.lang.String[]);
  Code:
   0:   aload_0
   1:   astore_1
   2:   aload_1
   3:   arraylength
   4:   istore_2
   5:   iconst_0
   6:   istore_3
   7:   iload_3
   8:   iload_2
   9:   if_icmpge   31
   12:  aload_1
   13:  iload_3
   14:  aaload
   15:  astore  4
   17:  getstatic   #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload   4
   22:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  iinc    3, 1
   28:  goto    7
   31:  return

A normal for loop:

 public static void normalPrint(java.lang.String[]);
  Code:
   0:   aload_0
   1:   astore_1
   2:   aload_1
   3:   arraylength
   4:   istore_2
   5:   iconst_0
   6:   istore_3
   7:   iload_3
   8:   iload_2
   9:   if_icmpge   31
   12:  aload_1
   13:  iload_3
   14:  aaload
   15:  astore  4
   17:  getstatic   #10; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload   4
   22:  invokevirtual   #11; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  iinc    3, 1
   28:  goto    7
   31:  return

As you can see, in both cases, the compiler is loading the arrays length (strs.length) and looping against it. We see that the enhanced for-each loop, in the case of an Array is syntactic sugar for looping against the array's length (rather than in an Object's case where it uses an Iterator).


I have edited the 'normal' for loop such that it is much less idiomatic, but that it has the same bytecode as the enhanced for loop. For all intents and purposes, the normal for loop version is what the compiler generates when it compiles the enhanced for each loop.

like image 68
Reese Moore Avatar answered Sep 22 '22 23:09

Reese Moore


Yes, there is something akin to the C++ sizeof operator -- it's the length instance variable (which gives the number of elements in the array, not the size in bytes.) The length field is always a public member of the array, so it is accessible to Java programmers.

And yes, arrays are objects, and not just internally.

(More broadly, the for loop syntax works as described in the question that org.life.java linked to; but that isn't quite what you were asking.)

like image 45
Dan Breslau Avatar answered Sep 20 '22 23:09

Dan Breslau