Java Reference
In-Depth Information
explaining what the corresponding value is, so you don't have to do that work yourself. Constant #17 is of
type NameAndType , which is the name and shape of the method. Like the class names, the particular name
and type information is represented by other strings in the constant pool. In this case, the name is "<init>,"
which is the magic bytecode name for constructors. The method's shape is that it takes no arguments (that's
the empty parenthesis, () ) and returns void ( V ). The last constant in the pool is a method reference, which
is going to be a Class combined with a NameAndType . That combination will uniquely define a method to
invoke. The value of constant #1 is defining to the Object default constructor method reference -we will see
why when we move to the next element of the classfile.
The body of the class is defined within brackets, just like in the Java language. The method names are
similar to the Java declaration: in our case, we have public static void main(java.lang.String[]);
and public Listing1(); . We have two methods in the bytecode, but we only have one method declared in
our Java code. What's the second method? The answer is that Java requires each class to have a constructor.
If you don't have a constructor, one will be provided to you by the compiler: namely, a default constructor
that takes no arguments and allows all the field values to be the default. Since we did not declare a
constructor, the compiler gave us one, and that is what "public Listing1();." is. Before we look into its
implementation, though, let's take a look at the method we did declare. The main method that we declared
in the Java code was empty, but there is a fair bit going on in the bytecode (lines 56-71):
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
line 3: 0
Start Length Slot Name Signature
0 1 0 args [Ljava/lang/String;
stack=0, locals=1, args_size=1
0: return
line 3: 0
Start Length Slot Name Signature
0 1 0 args [Ljava/lang/String;
After the declaration of the method is the descriptor. This is the official bytecode declaration of the
shape of the method. The arguments of the declaration are within parentheses: in this case, it is an array
of type java.lang.String . Object types in bytecode are given between the character “L” and the character
“;”. Packages are delimited by forward slashes instead of periods. Therefore, java.lang.String becomes
Ljava.lang.String; . Arrays are specified by an open square brace: “[”. Since the main method takes a single
array of type string, its argument type is therefore ([Ljava.lang.String;) . We again see the “V” dangling
at the end to represent the void return type. That gives you the whole descriptor, which is the signature of
the method. In programming language geek parlance, the signature of a method describes the method's
“shape”: the signature describes how the method can fit into the program as a whole, the same way a shape
of a puzzle piece determines how the piece fits into the puzzle.
The next line is again the flags. In this case, they correspond to the public and static keywords in
Java. Following that, we have a LineNumberTable for the method, which is effectively repeated in the Code
section below. This table is how debuggers know what line of code corresponds to what operation. In this
case, it is saying that line 3 of the source file is where the method is declared. After the LineNumberTable is
the LocalVariableTable, which stores the local variables, and which is also repeated in the Code section. Our
Search WWH ::

Custom Search