2.6 Declaring Methods

A method declaration is similar to a field declaration. Here is an example of a method declaration that computes the sum of two floats:

 .method public computeSum (FF)F .limit locals 3 .limit stack 2 fload_1                        ; Push the first argument fload_2                        ; Push the second argument fadd                           ; Add them together freturn                        ; Return the result 

The .method directive is structurally identical to the .field directive. It begins with a list of modifiers, followed by the name and the descriptor. The descriptor is a little different for methods. It's written as

 (type1type2...)typereturn 

where the list of typei is the types of the arguments and typereturn is the type of the return. Each of these types is one of the types in Table 2.2 for fields. There aren't any spaces between the arguments. Some examples are shown in Table 2.4.

Methods may have modifiers, just like fields. The available modifiers are different for methods. A summary of the method modifier keywords is given in Table 2.5 . The .method declaration continues until a .end method directive is found. In between .method and .end method are the instructions that make up the method. There are about 200 different instructions to do different things in the JVM. The instructions are the subject of the next few chapters.

In the computeSum example, the fload_1 and fload_2 instructions push values from local variables onto the stack. The fadd instruction adds the two float values on top of the operand stack, replacing them with the sum. The freturn returns the top of the stack.

Two special directives apply within method bodies: .limit stack and .limit locals. These tell the JVM how much space it should allocate for the method when it is executed: .limit stack limits the total height of the stack at any point, and .limit locals limits the size of the local variable array. Each may be as high as 65,536, but few programs require anywhere near that much space.

Table 2.4. Some method descriptors
Java method declaration Descriptor
void main(String argv[]) (Ljava/lang/String;)V
int read(byte[] data, int offset, int len) ([BII)I
String toString() ()Ljava/lang/String;
void println() ()V

Table 2.5. .method directive keywords
Keyword Meaning
public This method is available to all other classes.
private This method may be accessed only from within this class.
protected This method may be accessed from any class in the same package or any class that is a subclass of this class.
static This method is a class method.
final This method may not be overridden in subclasses.
synchronized The JVM will obtain a lock on this object before invoking the method. If this method is static, then the JVM will obtain a lock on the Class object corresponding to this class.
native This method is implemented in native code; no implementation is provided.
abstract This method has no implementation.
strictfp This method uses strict floating-point semantics. If not given, the implementation may use additional precision. (Ignored on pre-Java 2 platform JVMs.)

The number in the directive is the number of slots to reserve. A slot is big enough to hold an int, float, or reference value. It takes two slots to hold a long or double.

If the .limit directives aren't given, the Oolong assembler takes its best guess. The assembler errs on the side of caution rather than efficiency.

These limits aren't just suggestions. The JVM implementation will enforce them. If you try to use more stack space or more local variables than you requested, the virtual machine will refuse to execute the method. It can tell even without executing the code how many variables are used, since all of the instructions that affect the local variable array have the number of the slot incorporated into the instruction as an argument. (That is, the number of slots that are used in each instruction is fixed in the instruction itself, not computed when the program is run.) Thus, if the program contains the instruction

 lload 7 

it knows that at least nine variables are used (variables 0 through 7 plus one more, since the lload instruction affects both variables 7 and 8).

Measuring the maximum height of the stack just from looking at the code is a little harder, but it can be done. The enforcement is the job of the verification algorithm. See chapter 6 for more information about the verification algorithm.

You can have multiple methods with the same name as long as they have different descriptors:

 ;; A method to print a float value .method println(F)V ;; A method to print a String value .method println(Ljava/lang/String;)V ;; A method to print a long value .method println(J)V 

This is called method overloading. In Oolong, when a method is called you must specify the entire descriptor, including the return type. This means that you can have two methods that differ only in the return type:

 .method computeResult ()I      ; Return the result as an int .method computeResult ()D      ; Return the result as a double 

However, you won't be able to use the resulting class from Java programs, so the practice is discouraged.

In Java, two methods may not differ only in their return types. If you have two methods with the same name and identical arguments and different returns, it's an error. That's necessary because in Java methods are specified only by name. The Java compiler must infer which overloaded method is intended by looking at the types of the arguments. It isn't possible to infer using the return type, because it isn't always obvious from context. From this code

 float f = (float) computeResult();     // Which method? 

it is impossible to determine which version of computeResult is intended. Rather than creating some arcane rules, the Java designers simply ruled this illegal Java, even though it is legal for the JVM.

Exercise 2.5

The following represent method declarations in Java. What would the corresponding Oolong .method directives be?

 void printTable(OutputStream out, String entries[][]) protected synchronized Integer addInts(Integer i, Integer j) static native void shutdown() 

Exercise 2.6

Modify the example computeSum on page 35 to add three arguments instead of two.

Exercise 2.7

In the computeSum example, the method does not take advantage of variable 0, which is used to store the object on which the method was invoked (this).The method computeSum would be more efficient as a static method. Rewrite the method as a static method. Remember that the variable numbers must change.



Programming for the Java Virtual Machine
Programming for the Javaв„ў Virtual Machine
ISBN: 0201309726
EAN: 2147483647
Year: 1998
Pages: 158
Authors: Joshua Engel

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net