Brought to you by EarthWeb
ITKnowledge Logo Login Graphic Click here to enter the VB Zone
Click here to enter the VB Zone
ITKnowledge
Find:
 
EXPERT SEARCH ----- nav

EarthWeb Direct

EarthWeb sites: other sites

Previous Table of Contents Next


The next variant, Listing 4-2, was obtained by forcing the file open in a text processor (specifically BBEdit). The printout here has thrown away a few characters, such as page break (ASCII), that would have completely screwed up the formatting of this book. This looks awful, but it’s a quick-and-dirty way to get a look at the String constants in a file.

I remember a stock trader in the early days of PCs who didn’t like one of the messages that his program gave him, so he opened up the DOS .exe file in WordPerfect, searched for the offending string, replaced it, and saved the file. Amazingly, the program worked with his “user modification.” I do not recommend this as general practice. There’s not much else to be learned here, so let’s move on.

Listing 4-3 is composed of disassembled byte code. This is much more useful than Listing 4-2. You get to see the name of the class, all imported classes, and all methods and fields. With a little effort, you can learn to read the byte codes as you would read someone else’s source code. This listing was produced with the JDK’s javap program with the -c command line flag — that is:

   % javap -c HelloWorld

I’ll develop a different byte code disassembler later in this chapter and the next.

Why would you want to do this when you can look at the .java source code file instead? The short answer is that you’ll almost never do this instead of looking at the .java file. However, it’s not uncommon to want to investigate the code of a class for which you do not have original source code. You’ve probably become accustomed to using your Web browser’s View Source command to find out how someone did a neat HTML trick. With the techniques and tools you’ll develop in this chapter, you’ll have an effective View Source equivalent for Java .class files.

Let’s begin by looking at the source and byte codes for the main() method of the HelloWorld class.

     public static void main (String args[]) {     Method void main()

        System.out.println(“Hello World!”);
        0 getstatic #7 <Field java.lang.System.out Ljava/io/PrintStream;>
              3 ldc #1 <String “Hello World”>
                5 invokevirtual #8 <Method java.io.PrintStream.print(Ljava/lang/String;)V>
                8 return
      }

     }

Lining them up side-by-side, you can see that these four lines

      0 getstatic #7 <Field java.lang.System.out Ljava/io/PrintStream;>
      3 ldc #1 <String “Hello World”>
      5 invokevirtual #8 <Method java.io.PrintStream.print(Ljava/lang/String;)V>
      8 return

are probably somehow equivalent to the single source code line:

   System.out.println(“Hello World!”);

See if you can figure out how. The numbers on the left of each line start counting at zero. They’re indices into the byte codes for this method. This is just a series of bytes in a particular place in memory.

The first byte is an instruction: getstatic. The argument to this instruction is #7. This refers to the seventh entry in the constant pool for this class. It so happens that the seventh entry in this particular pool is java.lang.System.out, an instance of java.io.PrintStream. You know that System.out is a static field in the System class of type PrintStream, so it seems logical to interpret getstatic as a command to retrieve a reference to a static class. In this case, it retrieves a reference to the System.out class and places it on the stack.

The next instruction is ldc, which stands for “load constant.” It has one argument: the integer constant #1. The 1 tells it which constant to load from the constant pool. In this case, it loads the first constant in the pool, which happens to be the string “Hello World!” Because “Hello World” is the only constant literal in HelloWorld.java, it’s not surprising that it’s the first one in the pool. A reference to this string is placed on the top of the stack.

The next instruction is invokevirtual. This instruction calls instance methods. In this case, it calls the eighth entry in the constant pool, the method println() of the java.io.PrintStream class. The arguments for println() are taken from the stack. In this case, the top of the stack has a reference to the String object HelloWorld. The object whose method it should call is one level deeper in the stack. That’s the reference to System.out placed there by getstatic.

The last instruction is return. There was no return statement in main(), but Java puts one here anyway. Writing return is optional in void methods. The compiler is smart enough to add a blank return for you if your void method requires one. However, in a non-void method, you have to return explicitly, because the compiler, although it knows you have to return, does not know what value you want to return.

The next method is the constructor HelloWorld(). The .java source code file did not include a constructor. However, the compiler puts a default constructor that takes no arguments in the byte code anyway.

   Method HelloWorld()
     0 aload_0
     1 invokespecial #6 <Method java.lang.Object.<init>()V>
     4 return

   }

The aload instruction loads a reference from a local variable. In this case, it loads the zeroth local variable. This local variable is the string “java.lang.Object()”. This becomes the argument to the next instruction. The next instruction, invokespecial, is used to call the superclass’s constructor from the subclass’s constructor. Finally, the return instruction transfers control back to the calling method.

What’s most interesting about this method is that none of it is in the Java source code. All Java classes have a constructor that takes no arguments if there are no other explicit constructors. Furthermore, all constructors call their superclass’s constructor before they do anything else, even if there isn’t an explicit super() call in the first line of the subclass’s constructor.

In the remainder of this chapter, you’ll explore the Java .class file format to see how you change raw hexadecimal bytes such as those in Listing 4-1 into something more intelligible like the byte code in Listing 4-4.


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.