Brought to you by EarthWeb
ITKnowledge Logo Login Graphic Click Here!
Click Here!
ITKnowledge
Find:
 
EXPERT SEARCH ----- nav

EarthWeb Direct

EarthWeb sites: other sites

Previous Table of Contents Next


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 doesn’t 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 flags

The 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. (Don’t 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.

Table 4-2 Access flags

Bit Mask Meaning if set

0 0x8000 Reserved for future use.
1 0x4000 Reserved for future use.
2 0x2000 Reserved for future use.
3 0x1000 Reserved for future use.
4 0x0800 Reserved for future use.
5 0x0400 This is an abstract class or interface.
6 0x0200 This is an interface.
7 0x0100 Reserved for future use.
8 0x0080 Reserved for future use.
9 0x0040 Reserved for future use.
10 0x0020 This is treated specially by invokespecial.
11 0x0010 This class is final.
12 0x0008 Reserved for future use.
13 0x0004 Reserved for future use.
14 0x0002 Reserved for future use.
15 0x0001 This class or interface is public.

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 can’t 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?

thisClass

Next 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 you’re 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);
   }


Previous Table of Contents Next
HomeAbout UsSearchSubscribeAdvertising InfoContact UsFAQs
Use of this site is subject to certain Terms & Conditions.
Copyright (c) 1996-1999 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.