|
|
|||
|
|
|
|
|
|
Creating new objects Now that you know how to work with fields and methods in Java byte code, the only object instruction left is the creation of new objects. There is a single instruction to create new objects, the appropriately named new instruction. Listing 5-8 is a very simple class that does one thing: create a new java.lang.Integer object with the value 7. Listing 5-8 Create a new object
class newTest {
public void makeInteger() {
Integer i = new Integer(7);
}
}
Listing 5-9 shows the byte code for this example. Notice the new instruction at byte 0 of the makeInteger() method. This is followed by the two bytes of a signed short with the value 3. If you guessed that this 3 is an index into the constant pool, you are correct. Entry 3 in the constant pool is a ClassInfo structure that points to the UTF8 structure in entry 19 of the constant pool. That entry is java/lang/Integer, and it tells the new instruction to create a new object of type java.lang.Integer. The new instruction only allocates space for the object in the virtual machine. It does not initialize it. The constructor still needs to be called. Bytes 3 and 4 push the argument for the constructor onto the stack. Bytes 5 through 7 invoke the constructor with the invokespecial instruction. Finally, byte 8 returns void. Listing 5-9 Byte code for the new operator
class newTest extends java.lang.Object {
public void makeInteger() {
0 new
1 0
2 3
3 bipush
4 7
5 invokespecial
6 0
7 5
8 return
}
void <init>() {
0 aload_0
1 invokespecial
2 0
3 4
4 return
}
}
/*
1: ClassInfo 20
2: ClassInfo 22
3: ClassInfo 19
4: MethodRef ClassIndex: 1; NameAndTypeIndex: 7
5: MethodRef ClassIndex: 3; NameAndTypeIndex: 6
6: NameAndType NameIndex: 21; DescriptorIndex: 9
7: NameAndType NameIndex: 21; DescriptorIndex: 24
8: UTF8 this
9: UTF8 (I)V
10: UTF8 newTest.java
11: UTF8 ConstantValue
12: UTF8 LocalVariableTable
13: UTF8 Exceptions
14: UTF8 LineNumberTable
15: UTF8 SourceFile
16: UTF8 LocalVariables
17: UTF8 Code
18: UTF8 makeInteger
19: UTF8 java/lang/Integer
20: UTF8 java/lang/Object
21: UTF8 <init>
22: UTF8 newTest
23: UTF8 LnewTest;
24: UTF8 ()V
*/
ArraysIn Java, arrays are objects and array variables are references. However, there are four byte codes that operate specifically on arrays. The newarray instruction allocates new arrays of primitive types such as int and double. The anewarray instruction allocates new arrays of references. The multianewarray instruction allocates multidimensional arrays of any type. The arraylength instruction returns the length of an array. The iaload, laload, faload, daload, aaload, baload, caload, and saload instructions copy values from an array onto a stack. The iastore, lastore, fastore, dastore, aastore, bastore, castore, and satore instructions pop values from the stack and put them in an array. Creating arrays When you write a statement like
int[] e = new int[7];
Java must allocate the right amount of space in the heap for an array of seven ints. To do this, it first pushes the value 7 onto the stack. Then it uses the newarray instruction to actually allocate the space. The number of ints to allocate is popped from the stack. The type of the array to allocate is read from the next byte in the code array. An int array is type 11. A reference to the array is pushed onto the stack. This reference is then popped from the stack and copied into whichever position e occupies in the local variable array. Thus, the byte code would look something like this:
bipush
7
newarray
11
astore_1
The newarray instruction knows the sizes of the different types it can hold and allocates the appropriate amount of space.
Arrays are one of the few areas in Java in which all primitive data types are supported equally. Short arrays really are arrays of shorts and not just a subset of ints. Although the difference in storage requirements between a single short variable and a single int variable is trivial on modern computers, the difference between a large array of shorts and a large array of ints can still be significant. anewarray Arrays of objects are really arrays of references. The type of such an array is given as a 2-byte index into the constant pool that follows the anewarray instruction. Like the newarray instruction, the length of the array is popped from the stack, and a reference to the new array is pushed onto the stack. Thus,
Integer[] e = new Integer[7];
might compile to something like this:
0 bipush
1 7
2 anewarray
3 0
4 3
5 astore_1
...
/* Constant Pool
1: ClassInfo 21
2: ClassInfo 23
3: ClassInfo 20
...
20: UTF8 java/lang/Integer
...
The difference between newarray and anewarray is that newarray encodes the type of the data directly into the code array, whereas anewarray needs to refer to the constant pool.
|
|||||||||||||||||||||||||||||||
|
|
|