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


Import statements

There’s no one place in a .class file where all the import statements are stored. To determine which import statements were in the source code, you have to list all the classes in the constant pool. You might choose to output one import statement for each class, or you might be somewhat more selective. In this example, I have chosen not to produce import statements for the class itself or any classes in java.lang. This makes the disassembled source code more similar to what you actually write in programs. If you wanted to, you could include import statements only for entire packages (for example, import java.util.*) rather than for individual classes. However, I find it convenient to be able to see exactly what classes a particular class references.

To find the classes, you loop through the constant pool and check each entry to see if it’s a ClassInfo structure. It’s important to remember that the zeroth entry in the constant pool is not included in the .class file. When a ClassInfo structure is found, you use its nameIndex() method to get the class’s name as a UTF8 structure from the constant pool. Each name thus retrieved is tested to be sure that it’s not the name of this class and that it’s not a class from java.lang. Assuming neither of these is the case, an import statement for the class is printed. Listing 4-25 demonstrates the writeImports() method.

Listing 4-25 The writeImports() method

   public void writeImports() {

    PoolEntry pe = null;
    String thisname =  thePool.readUTF8(thisClass.nameIndex());
    // recall that there’s nothing in the zeroth pool entry
    for (int i = 1; i < thePool.howMany(); i++) {
     pe = thePool.read(i);
     if (pe.tag() == PoolEntry.cClassInfo) {
      ClassInfo ci = pe.readClassInfo();
      String name = thePool.readUTF8(ci.nameIndex());
      name = name.replace(‘/’,’.’);
       postedif (!name.startsWith(“java.lang.”) && !name.equals(thisname)) {
        theOutput.println(“import “ + name + “;”);
      }
     }
    }

    theOutput.println();

   }

Access specifiers

The writeAccess() method looks at the access specifiers for the class and prints them in Java form. Listing 4-26 has the code.

Listing 4-26 The writeAccess() method

   public void writeAccess() {

    if (isPublic) theOutput.print(“public “);
    if (isFinal) theOutput.print(“final “);
    if (isAbstract) theOutput.print(“abstract “);
    if (isInterface) theOutput.print(“interface “);
    else theOutput.print(“class “);

   }

Note that if a .class file is not an interface, then it must represent a class. Note also that one access flag, isSpecial, has no equivalent in Java source code. It exists only for the use of the compiler and the virtual machine.

Class and superclass

The next thing you want to know is the name of the class. You can easily retrieve this from the thisClass field, which points to the name of the class in UTF8 format in the constant pool (see Listing 4-27).

Listing 4-27 The writeClassName() method

   public void writeClassName() {

    String name = thePool.readUTF8(thisClass.nameIndex());
    theOutput.print(name + “ “);
   }

Next, you want to find out which class this class extends (see Listing 4-28). You have to watch out for the special case of java.lang.Object, which has no superclass. Otherwise, this is very similar to the previous method.

Listing 4-28 The writeSuperclass() method

   public void writeSuperclass() {

    if (superclass.nameIndex() != 0) {
     String name = thePool.readUTF8(superclass.nameIndex());
     theOutput.print(“extends “ + name + “ “);
    }

   }

Interfaces

The interfaces are similar except that there may be more than one of them. When you’re finished outputting all the interfaces, open the class with an opening brace. The writeInterfaces() method is shown in Listing 4-29.

Listing 4-29 The writeInterfaces() method

   public void writeInterfaces() {

    if (interfaces.length > 0) {
     String name = thePool.readUTF8(interfaces[0].nameIndex());
     theOutput.print(“implements “ + name + “ “);
     for (int i=1; i < interfaces.length; i++) {
      name =  thePool.readUTF8(interfaces[i].nameIndex());
      theOutput.print(“, “ + name);
     }
    }
    theOutput.println(“ {“);
   }

I’ve chosen to put the access specifiers, the class name, the class that this extends, all interfaces that this class implements, and the opening brace on a single line of the file. This produces output that looks like:

   public final class myVector extends java.util.Vector implements java.io.Serializable {

Feel free to adjust this to match your preferences. For example, some people prefer to write each of these on separate lines.

   public final class myVector
    extends java.util.Vector
    implements java.io.Serializable
    {

Both versions produce identical byte code, so when you’re working backward from the byte code, there’s no way to distinguish the two cases.


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.