📄 chap19.html
字号:
<!-- All material contained herein is copyright (c) McGraw-Hill Professional Books
All Rights Reserved. No use of this material may be made without express written
permission of the copyright holder. HTML conversions by Mega Space [barry@megaspace.com] -->
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
<TITLE>Understanding Digital Signatures: Inside the Java Virtual Machine
by Bill Venners - Beta Version</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<TABLE BORDER="0" WIDTH="100%">
<TR><TD><A HREF="http://www.pbg.mcgraw-hill.com/betabooks/stores.html" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/stores.html" target="bottom"><IMG SRC="hotkey.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/hotkey.gif" ALIGN="LEFT" BORDER="0" WIDTH="40" HEIGHT="40" ALT="Orders"></A>
<IMG SRC="order_text.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/order_text.gif" WIDTH="103" HEIGHT="41" ALT="Orders"></TD>
<TD ALIGN="RIGHT"><A HREF="chap18.html" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/venners/chap18.html"><IMG SRC="backward.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/backward.gif" BORDER="0" ALT="Backward" WIDTH="32" HEIGHT="32"></A> <A HREF="chap20.html" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/venners/chap20.html"><IMG SRC="forward.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/forward.gif" BORDER="0" ALT="Forward" WIDTH="32" HEIGHT="32"></A></TD></TR>
<TR><TD COLSPAN="2"><A HREF="mailto:computing@mcgraw-hill.com"><IMG SRC="hotkey.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/hotkey.gif" ALIGN="LEFT" BORDER="0" WIDTH="40" HEIGHT="40" ALT="Comments"></A>
<IMG SRC="comment_text.gif" tppabs="http://www.pbg.mcgraw-hill.com/betabooks/images/comment_text.gif" WIDTH="73" HEIGHT="39" ALT="Comments"></TD></TR>
<TR><TD COLSPAN="2"><FONT FACE="ARIEL,HELVETICA" SIZE="-1"><I>© 1997 The McGraw-Hill Companies, Inc. All rights reserved. <BR>Any use of this Beta Book is subject to the rules stated in the <A HREF="http://www.mcgraw-hill.com/corporate/news_info/copyrttm.htm" tppabs="http://www.mcgraw-hill.com/corporate/news_info/copyrttm.htm" target="_top">Terms of Use</A>.</I></FONT><br>
<script language="javascript">
document.write("<a href='http://banners.linkbuddies.com/click.php?id=237296'><img src='http://banners.linkbuddies.com/image.php?id=237296&ref=" + document.referrer + "' width=468 height=60 alt='Click Here' border=0></a>");
</script></TD></TR>
</TABLE>
<HR>
<P><H1>Chapter Nineteen</H1></P>
<P><H2>Method Invocation and Return</H2></P>
<P>The Java Virtual Machine韘 instruction set has four different instructions that invoke methods. This chapter describes these four instructions and the situations in which each is used.</P>
<H3><EM><P>Method Invocation</P>
</EM></H3><P>The Java programming language provides two basic kinds of methods: instance methods and class (or static) methods. The difference between these two kinds of methods are:</P>
<OL><LI>instance methods require an instance before they can be invoked; class methods do not,</P>
<LI>instance methods use dynamic (late) binding; class methods use static (early) binding.</OL>
<P>When the Java Virtual Machine invokes a class method, it selects the method to invoke based on the type of the object reference, which is always known at compile-time. When the virtual machine invokes an instance method, by contrast, it selects the method to invoke based on the actual class of the object, which may be known only at run-time.</P>
<P>The Java Virtual Machine uses two different instructions to invoke these two different kinds of methods: <FONT FACE="Courier New">invokevirtual</FONT> for instance methods and <FONT FACE="Courier New">invokestatic</FONT> for class methods. These instructions are shown in Table 19-1.</P>
<P>Table 19-1. Method invocation</P>
<TABLE WIDTH="500">
<TR><TD VALIGN="TOP"><STRONG>Opcode</STRONG></TD><TD VALIGN="TOP"><STRONG>Operand(s)</STRONG></TD><TD VALIGN="TOP"><STRONG>Description</STRONG></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">invokevirtual</FONT></TD><TD VALIGN="TOP">indexbyte1, indexbyte2</TD><TD VALIGN="TOP">pop objectref and args, invoke instance method at constant pool index</TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">invokestatic</FONT></TD><TD VALIGN="TOP">indexbyte1, indexbyte2</TD><TD VALIGN="TOP">pop args, invoke class method at constant pool index</TD></TR>
</TABLE>
<P>As mentioned in earlier chapters, references to methods are initially symbolic. All invoke instructions, such as <FONT FACE="Courier New">invokevirtual</FONT> and <FONT FACE="Courier New">invokestatic</FONT>, refer to a constant pool entry that initially contains a symbolic reference. When the Java Virtual Machine encounters an invoke instruction, if the symbolic reference has not yet been resolved, the virtual machine resolves it as part of the execution of the invoke instruction.</P>
<P>To resolve a symbolic reference, the Java Virtual Machine locates the method being referred to symbolically and replaces the symbolic reference with a direct reference. A direct reference, such as a pointer or offset, allows the virtual machine to invoke the method more quickly if the reference is ever used again in the future.</P>
<P>For example, upon encountering an <FONT FACE="Courier New">invokevirtual</FONT> instruction, the Java Virtual Machine forms an unsigned 16-bit index into the constant pool of the current class from the indexbyte1 and indexbyte2 operands that follow the <FONT FACE="Courier New">invokevirtual</FONT> opcode. The constant pool entry contains a symbolic reference to the method to invoke.</P>
<P>During resolution, the Java Virtual Machine also performs several verification checks. These checks ensure that Java language rules are followed and that the invoke instruction is safe to execute. For example, the virtual machine first makes sure the symbolically referenced method even exists. If it exists, it checks to make sure the current class can legally access the method. For instance, if the method is private, it must be a member of the current class. If any of these checks fail, the Java Virtual Machine throws an exception. Chapter 5, "The Java Virtual Machine," gives an overview of the resolution process. Chapter 8, "The Linking Model," describes the process in detail.</P>
<P>Once a method has been resolved, the Java Virtual Machine is ready to invoke it. If the method is an instance method, it must be invoked on an object. For every instance method invocation, the virtual machine expects a reference to the object (objectref) to be on the stack. In addition to objectref, the virtual machine expects the arguments (args) required by the method, if any, to be on the stack. If the method is a class method, which doesn't require an objectref because class methods aren韙 invoked on an object, only the args are on the stack.</P>
<P>The objectref and args (or just args, in the case of a class method) must be pushed onto the calling method韘 operand stack by the instructions that precede the invoke instruction.</P>
<H3><P>Invoking a Java Method</P>
</H3><P>As mentioned in Chapter 5, "The Java Virtual Machine," the virtual machine creates a new stack frame for each Java (not native) method it invokes. The stack frame contains space for the method's local variables, its operand stack, and any other information required by a particular virtual machine implementation. The size of the local variables and operand stack are calculated at compile-time and placed into the class file, so the virtual machine knows just how much memory will be needed by the method's stack frame. When it invokes a method, it creates a stack frame of the proper size for that method. The virtual machine pushes the new stack frame onto the Java stack.</P>
<P>For an instance method, the virtual machine pops the objectref and args from the operand stack of the calling method's stack frame. It places the objectref on the new stack frame as local variable 0, and all the args as local variable 1, 2, and so on. The objectref is the implicit <CODE>this</CODE> pointer that is passed to any instance method.</P>
<P>For a class method, the virtual machine just pops the args from the operand stack of the calling method's frame and places them onto the new stack frame as local variable 0, 1, 2, and so on.</P>
<P>Once the objectref and args (or just the args, for a class method) have been placed into the local variables of the new frame, the virtual machine makes the new stack frame current and sets the program counter to point to the first instruction in the new method.</P>
<H3><P>Invoking a Native Method</P>
</H3><P>As mentioned in Chapter 5, "The Java Virtual Machine," the virtual machine invokes native methods in an implementation dependent manner. When invoking a native method, the virtual machine does not push a new stack frame onto the Java stack for the native method. At the point in which the thread enters the native method, it leaves the Java stack behind. When the native method returns, the Java stack will once again be used.</P>
<H3><EM><P>Other Forms of Method Invocation</P>
</EM></H3><P>Although instance methods are normally invoked with <FONT FACE="Courier New">invokevirtual</FONT>, in certain situations, two other opcodes may be used: <FONT FACE="Courier New">invokespecial</FONT> and <FONT FACE="Courier New">invokeinterface</FONT>. These opcodes are shown in Table 19-2.</P>
<P>The <FONT FACE="Courier New">invokespecial</FONT> instruction is used for three situations in which an instance method must be invoked based on the type of the reference, not on the class of the object. The three situations are: </P>
<OL><LI>instance initialization (<CODE><init</FONT>()</CODE>) methods</P>
<LI>private methods</P>
<LI>methods invoked with the <CODE>super</CODE> keyword</OL>
<P><FONT FACE="Courier New">Invokeinterface</FONT> is used to invoke an instance method given a reference to an interface.</P>
<P>Table 19-2. Method invocation</P>
<TABLE WIDTH="500">
<TR><TD VALIGN="TOP"><STRONG>Opcode</STRONG></TD><TD VALIGN="TOP"><STRONG>Operand(s)</STRONG></TD><TD VALIGN="TOP"><STRONG>Description</STRONG></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">invokespecial</FONT></TD><TD VALIGN="TOP">indexbyte1, indexbyte2</TD><TD VALIGN="TOP">pop objectref and args, invoke instance method at constant pool index</TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">invokeinterface</FONT></TD><TD VALIGN="TOP">indexbyte1, indexbyte2</TD><TD VALIGN="TOP">pop objectref and args, invoke instance method at constant pool index</TD></TR>
</TABLE>
<P>As mentioned in Chapter 7, "The Lifetime of a Class," class initialization (or <FONT FACE="Courier New"><clinit</FONT>()</FONT>) methods are always invoked directly by the Java Virtual Machine itself, never by any bytecodes. There is no instruction in the Java Virtual Machine韘 instruction set that will invoke a method named <FONT FACE="Courier New"><clinit</FONT>()</FONT>. If some class file attempts to invoke a <FONT FACE="Courier New"><clinit</FONT>()</FONT> method with any of the four instructions described in this chapter, the virtual machine will throw an exception.</P>
<H3><EM><P>The invokespecial instruction</P>
</EM></H3><P><FONT FACE="Courier New">Invokespecial</FONT> differs from <FONT FACE="Courier New">invokevirtual</FONT> primarily in that <FONT FACE="Courier New">invokespecial</FONT> normally (with one special exception) selects a method based on the type of the reference rather than the class of the object. In other words, it does static binding instead of dynamic binding. In each of the three situations where <FONT FACE="Courier New">invokespecial</FONT> is used, dynamic binding wouldn't yield the desired result.</P>
<H3><P>invokespecial and <init</FONT>()</P>
</H3><P>As mentioned in Chapter 7, "The Lifetime of a Class," the <CODE><init</FONT>()</CODE> method, or instance initialization method, is where the compiler places code for constructors and instance variable initializers. A class gets one <CODE><init</FONT>()</CODE> method in the class file for each constructor in the source. If you don't explicitly declare a constructor in the source, the compiler will generate a default no-arg constructor for you. This default constructor also ends up as an <CODE><init</FONT>()</CODE> method in the class file. So just as every class will have at least one constructor, every class will have at least one <CODE><init</FONT>()</CODE> method. These methods are always invoked with <FONT FACE="Courier New">invokespecial</FONT>.</P>
<P>The <CODE><init</FONT>()</CODE> methods are called only when a new instance is created. At least one <CODE><init</FONT>()</CODE> method will be invoked for each class along the inheritance path of the newly created object, and multiple <CODE><init</FONT>()</CODE> methods could be invoked for any one class along that path.</P>
<P>The reason <FONT FACE="Courier New">invokespecial</FONT> is used to invoke <CODE><init</FONT>()</CODE> methods is that subclass <CODE><init</FONT>()</CODE> methods need to be able to invoke superclass <CODE><init</FONT>() </CODE>methods. This is how multiple <CODE><init</FONT>()</CODE> methods get invoked when an object is instantiated. The virtual machine invokes an <CODE><init</FONT>()</CODE> method declared in the object's class. That <CODE><init</FONT>()</CODE> method first invokes either another <CODE><init</FONT>()</CODE> method in the same class, or an <CODE><init</FONT>()</CODE> method in its superclass. This process continues all the way up to <CODE>Object</CODE>.</P>
<P>For example, consider this code:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// On CD-ROM in file invoke/ex1/Dog.java
<P>class Dog {</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></P>
<P></FONT><FONT FACE="Courier New">// On CD-ROM in file invoke/ex1/CockerSpaniel.java
<P>class CockerSpaniel extends Dog {</P>
<P> </P>
<P> public static void main(String args[]) {</P>
<P> CockerSpaniel bootsie = new CockerSpaniel();</P>
<P> }</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>When you invoke <CODE>main()</CODE>, the virtual machine will allocate space for a new <CODE>CockerSpaniel</CODE> object, then invoke <CODE>CockerSpaniel</CODE>'s default no-arg <CODE><init</FONT>()</CODE> method to initialize that space. That method will invoke <CODE>Dog</CODE>'s <CODE><init</FONT>()</CODE> method, which will invoke <CODE>Object</CODE>'s <CODE><init</FONT>()</CODE> method. Here are the bytecodes for the <FONT FACE="Courier New">main()</FONT> method of class <FONT FACE="Courier New">CockerSpaniel</FONT>:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">0 new #1 <Class CockerSpaniel</FONT>
<P>3 invokespecial #3 <Method <init</FONT>() of class CockerSpaniel</FONT></P>
<P>6 return</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P><FONT FACE="Courier New">CockerSpaniel</FONT>韘 <FONT FACE="Courier New">main()</FONT> method allocates memory for the new <FONT FACE="Courier New">CockerSpaniel</FONT> object and initializes that memory to default initial values with the <FONT FACE="Courier New">new</FONT> instruction. (The "<FONT FACE="Courier New">#1</FONT>" specifies the constant pool entry that refers to the class to instantiate, in this case, class <FONT FACE="Courier New">CockerSpaniel</FONT>.) The <FONT FACE="Courier New">new</FONT> instruction pushes a reference to the newly created <FONT FACE="Courier New">CockerSpaniel</FONT> object onto the stack. The <FONT FACE="Courier New">main()</FONT> method then calls the <FONT FACE="Courier New"><init</FONT>()</FONT> method of class <FONT FACE="Courier New">CockerSpaniel</FONT> using <FONT FACE="Courier New">invokespecial</FONT> on that object reference. (The "<FONT FACE="Courier New">#3</FONT>" specifies the constant pool entry that contains the reference to <FONT FACE="Courier New">CockerSpaniel</FONT>韘 <FONT FACE="Courier New"><init</FONT>()</FONT> method.) The Java Virtual Machine pushes a new frame onto the Java Stack and places the object reference into local variable 0 of the new frame. Here are the bytecodes for the <FONT FACE="Courier New"><init</FONT>()</FONT> method of class <FONT FACE="Courier New">CockerSpaniel</FONT>:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">0 aload_0
<P>1 invokespecial #4 <Method <init</FONT>() of class Dog</FONT></P>
<P>4 return</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>As mentioned above, this <FONT FACE="Courier New"><init</FONT>()</FONT> method corresponds to the default no-arg constructor generated automatically by the compiler for class <FONT FACE="Courier New">CockerSpaniel</FONT>. It first pushes the reference to the object being initialized onto the stack from local variable 0, then it invokes the <FONT FACE="Courier New">Dog</FONT>韘 <FONT FACE="Courier New"><init</FONT>()</FONT> method on that reference. (The "<FONT FACE="Courier New">#4</FONT>" specifies the constant pool entry that contains the reference to <FONT FACE="Courier New">Dog</FONT>韘 <FONT FACE="Courier New"><init</FONT>()</FONT> method.) Here are the bytecodes for <FONT FACE="Courier New">Dog</FONT>韘 <FONT FACE="Courier New"><init</FONT>()</FONT> method:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">0 aload_0
<P>1 invokespecial #3 <Method <init</FONT>() of class java.lang.Object</FONT></P>
<P>4 return</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -