![]() |
|||
![]() ![]() |
![]() |
|
![]() |
multianewarray The multianewarray instruction creates multidimensional arrays of both primitive and reference types. The multianewarray instruction is similar to the anewarray instruction. The type of the array is read from the constant pool. The index into the constant pool is a 2-byte short that immediately follows the multianewarray instruction. Following this is an unsigned byte that contains the number of dimensions in the array. Multidimensional arrays of primitive types such as int or double are listed in the constant pool as a series of left brackets, one for each dimension, followed by a letter for the type. Thus, a two-dimensional array of ints (int[][]) is listed as [[I, and a three-dimensional array of doubles (double[][][]) is listed as [[[D. Table 5-4 lists the abbreviations for the different primitive data types.
A line of code like this int[][] i = new int[7][6]; might be compiled like this: ... 0 bipush 1 7 2 bipush 3 6 4 multianewarray 5 0 6 3 7 2 8 astore_1 ... /* Constant Pool 1: ClassInfo 16 2: ClassInfo 19 3: ClassInfo 17 ... 17: UTF8 [[I ... Accessing components of arrays Its not enough just to create arrays. You also have to be able to put values in the arrays (storing) and get values out of the arrays (loading). Loading There are eight instructions to copy values from an array onto the operand stack, one for each primitive data type except boolean and one for reference types. These instructions operate purely on the stack. Each pops the index of the component to load from the array and a reference to the array from the stack. Then, the component at that index in the array is pushed onto the stack. Figure 5-43 demonstrates with the iaload instruction:
The aaload, saload, caload, and faload instructions behave identically, except that they operate on arrays of type reference, short, char, and float, respectively, and push those types onto the stack. As usual, shorts and chars are zero-extended to ints before being pushed onto the stack. The baload instruction does double duty for loading both bytes and booleans. The result is sign-extended to an int. Otherwise, baload behaves exactly like iaload. The daload and laload instructions copy doubles and longs from an array onto the stack. Of course, each requires two words on the stack for the result. Figure 5-44 demonstrates with the daload instruction.
Storing There are eight instructions to pop values from the operand stack and store them in an array, one for each primitive data type except boolean and one for reference types. These instructions operate purely on the stack. Each pops three values from the stack, the value to be placed in the array, the index at which to place it, and a reference to the array in that order. Nothing is pushed back onto the stack. Then the value is stored in at that index in the array. Figure 5-45 demonstrates with the iastore instruction.
The aastore and fastore instructions behave identically, except that they operate on arrays of type reference and float respectively and pop those types onto the stack. The sastore and castore instructions pop a 4-byte int from the stack, lop off the high-order two bytes, and store the result in the referenced array. As long as the value actually fits in a short or a char, this is transparent and works exactly as does the iastore instruction. However, as discussed in Chapter 2, you encounter problems with int values above 32,767 or below -32,768. The bastore instruction stores both bytes and booleans. It pops a 4-byte int, an index, and a reference to an array from the stack, truncates the int to 1-byte, and stores the truncated result at the indexed position in the referenced array. The dastore and lastore pop doubles and longs from the stack and store them in an array. These instructions pop four words from the stack: the low-order four bytes of the value, the high-order four bytes of the value, the index into the array, and a reference to an array. Figure 5-46 demonstrates with the lastore instruction.
arraylength The arraylength instruction pops a reference to an array from the stack, checks the length of the array, and pushes the result back onto the stack. This instruction is used when you access the length member of an array. For example, its common to loop through all the command line arguments to main like this: public static void main(String[] args) { for (int j = 0; j < args.length; j++) { // do something with each argument } } The length of the args array is taken by pushing a reference to args onto the stack, executing the arraylength instruction, and then popping the result. Heres the byte code: public static void main(java.lang.String[]) { 0 iconst_0 1 istore_1 2 goto 3 0 4 6 5 iinc 6 1 7 1 8 iload_1 9 aload_0 10 arraylength 11 if_icmplt 12 -1 13 -6 14 return } Because main() is a static method, the zeroth component of the local variable array is the first argument to the method, not a reference to the current object. In other words, its a reference to the args array. Thus, byte 9 aload_0 pushes a reference to args onto the operand stack. Byte 10 arraylength pops that reference from the stack and pushes the length of the array onto the stack.
|
![]() |
|