![]() |
|||
![]() ![]() |
![]() |
![]()
|
![]() |
The PoolEntry class has 11 methods to return values. Each of these methods first checks to make sure that the type requested is in fact the type of this object. If the type doesnt match, then a ClassFormatError is thrown. Once it verifies the type, it converts the data array into a primitive type or object of the appropriate type. In four cases, a new class is required to hold the return type. The ClassInfo class holds a tag and an index into the constant pool for the name of the class. It appears in Listing 4-13. Listing 4-13 The ClassInfo class public class ClassInfo { int nameIndex; int tag; public ClassInfo(int t, int n) { tag = t; nameIndex = n; } public int nameIndex() { return nameIndex; } } The RefInfo class, shown in Listing 4-14, holds indices for the class and the NameAndType in the constant pool. This is used for method references, field references, and interface method references. Listing 4-14 The RefInfo class public class RefInfo { int classIndex; int nameAndTypeIndex; int tag; public RefInfo(int t, int c, int n) { tag = t; classIndex = c; nameAndTypeIndex = n; } public int classIndex() { return classIndex; } public int nameAndTypeIndex() { return nameAndTypeIndex; } } Finally, the NameAndType class shown in Listing 4-15 holds indices into the constant pool for a name and a descriptor. Listing 4-15 The NameAndType class public class NameAndType { int nameIndex; int descriptorIndex; int tag; public NameAndType(int t, int c, int n) { tag = t; nameIndex = c; descriptorIndex = n; } public int nameIndex() { return nameIndex; } public int descriptorIndex() { return descriptorIndex; } } Access flagsThe access flags listed in Table 4-2 are stored in the .class file as a 2-byte bit mask. Bit 15 (the ones bit) is set if the class is public. Bit 11 (the sixteens bit) is set if the class is final. Bit 10 is set if invokespecial needs to treat the class specially. (Dont worry too much about that. I explain what that means in the next chapter.) Bit 6 is set if the class is an interface. Bit 5 is set if the class is abstract. The remaining bits are not yet used.
These flags are not independent of each other. If bit 6 is set (this is an interface), then bit 5 must also be set, because all interfaces are abstract. Similarly, a class cannot have both bits 11 and 6 set, because a final class cant be abstract. The unused bits in the access flags are reserved for future use. For now, you should ignore them when parsing the file. Listing 4-16 provides the filled-out code to read the access flags. Listing 4-16 also introduces several new boolean fields to allow later methods to know the values of these flags. Listing 4-16 Reading the access flags short access_flags; boolean isPublic; boolean isFinal; boolean isInterface; boolean isAbstract; boolean isSpecial; void readAccessFlags() throws IOException { access_flags = theInput.readShort(); isPublic = (access_flags & 0x0001) == 0 ? false : true; isFinal = (access_flags & 0x0010) == 0 ? false : true; isInterface = (access_flags & 0x0020) == 0 ? false : true; isAbstract = (access_flags & 0x0200) == 0 ? false : true; isSpecial = (access_flags & 0x0400) == 0 ? false : true; if (isAbstract && isFinal) { throw new ClassFormatError(This class is abstract and final!); } if (isInterface && !isAbstract) { throw new ClassFormatError(This interface is not abstract!); } if (isFinal && isInterface) { throw new ClassFormatError(This interface is final!); } } There are a few things to note about this code. First, it is necessary to make an explicit comparison with == and ?: to zero in order to convert the masked short to a boolean. In a language like C or C++, you would simply take zero to mean false. The next thing to ask yourself is whether the final if clause is really necessary. Given that this code will throw an error if a class is abstract and final or if a class is an interface and not abstract, can it possibly reach the test for being both final and an interface? thisClassNext is a 2-byte unsigned short that is an index into the constant pool. At that index in the constant pool, you should find a ClassInfo structure. This ClassInfo structure represents the current class or interface that youre parsing. Listing 4-17 reads this index and stores the ClassInfo structure it references in a new field: thisClass. Notice how we have to refer back to the constant pool at this point. Listing 4-17 readClass() ClassInfo thisClass; void readClass() throws IOException { int index = theInput.readUnsignedShort(); thisClass = thePool.readClassInfo(index); }
|
![]() |
|