📄 15.doc.html
字号:
t.z()=1 when t holds a class T at run time.
<a name="37244"></a>s.z()=0 when s holds a class S at run time.
<a name="37245"></a>s.z()=1 when s holds a class T at run time.
</pre><a name="37254"></a>
The last line shows that, indeed, the method that is accessed <i>does</i> depend on the
run-time class of referenced object; when <code>s</code> holds a reference to an object of class
<code>T</code>, the expression <code>s.z()</code> refers to the <code>z</code> method of class <code>T</code>, despite the fact that the
type of the expression <code>s</code> is <code>S</code>. Method <code>z</code> of class <code>T</code> overrides method <code>z</code> of class <code>S</code>.
<p><a name="22234"></a>
The following example demonstrates that a null reference may be used to access a class (<code>static</code>) variable without causing an exception:<p>
<pre><a name="37293"></a>
class Test {
<a name="37294"></a> static String mountain = "Chocorua";
<a name="37295"></a>
static Test favorite(){
<a name="37296"></a> System.out.print("Mount ");
<a name="37297"></a> return null;
<a name="37298"></a> }
<a name="37299"></a>
public static void main(String[] args) {
<a name="37300"></a> System.out.println(favorite().mountain);
<a name="37301"></a> }
<a name="37302"></a>}
</pre><a name="22242"></a>
It compiles, executes, and prints:
<p><pre><a name="22243"></a>Mount Chocorua
</pre><a name="39173"></a>
Even though the result of <code>favorite()</code> is <code>null</code>, a <code>NullPointerException</code> is <i>not</i>
thrown. That "<code>Mount </code>" is printed demonstrates that the <i>Primary</i> expression is
indeed fully evaluated at run time, despite the fact that only its type, not its value,
is used to determine which field to access (because the field <code>mountain</code> is <code>static</code>).
<p><a name="20860"></a>
<h3>15.10.2 Accessing Superclass Members using <code>super</code></h3>
<a name="20451"></a>
The special form using the keyword <code>super</code> is valid only in an instance method or
constructor, or in the initializer of an instance variable of a class; these are exactly
the same situations in which the keyword <code>this</code> may be used <a href="15.doc.html#31980">(§15.7.2)</a>. The form
involving <code>super</code> may not be used anywhere in the class <code>Object</code>, since <code>Object</code> has
no superclass; if <code>super</code> appears in class <code>Object</code>, then a compile-time error results.
<p><a name="37384"></a>
Suppose that a field access expression <code>super.</code><i>name</i> appears within class <i>C</i>, and the immediate superclass of <i>C</i> is class <i>S</i>. Then <code>super.</code><i>name</i> is treated exactly as if it had been the expression <code>((</code><i>S</i><code>)this).</code><i>name</i>; thus, it refers to the field named <i>name</i> of the current object, but with the current object viewed as an instance of the superclass. Thus it can access the field named <i>name</i> that is visible in class <i>S</i>, even if that field is hidden by a declaration of a field named <i>name</i> in class <i>C</i>.<p>
<a name="20763"></a>
The use of <code>super</code> is demonstrated by the following example:<p>
<pre><a name="20487"></a>
interface I { int x = 0; }
<a name="20490"></a>class T1 implements I { int x = 1; }
<a name="50230"></a>class T2 extends T1 { int x = 2; }
<a name="20497"></a>class T3 extends T2 {
<a name="20498"></a> int x = 3;
<a name="20500"></a> void test() {
<a name="20502"></a> System.out.println("x=\t\t"+x);
<a name="20503"></a> System.out.println("super.x=\t\t"+super.x);
<a name="20504"></a> System.out.println("((T2)this).x=\t"+((T2)this).x);
<a name="20505"></a> System.out.println("((T1)this).x=\t"+((T1)this).x);
<a name="20506"></a> System.out.println("((I)this).x=\t"+((I)this).x);
<a name="20512"></a> }
<a name="20513"></a>}
<a name="20514"></a>class Test {
<a name="20515"></a> public static void main(String[] args) {
<a name="20516"></a> new T3().test();
<a name="20518"></a> }
<a name="20519"></a>}
</pre><a name="20520"></a>
which produces the output:
<p><pre><a name="20521"></a>
x= 3
<a name="20522"></a>super.x= 2
<a name="20523"></a>((T2)this).x= 2
<a name="20524"></a>((T1)this).x= 1
<a name="20525"></a>((I)this).x= 0
</pre><a name="37491"></a>
Within class <code>T3</code>, the expression <code>super.x</code> is treated exactly as if it were:
<p><pre><a name="37492"></a><code>((T2)this).x
</code></pre><a name="20448"></a>
<h2>15.11 Method Invocation Expressions</h2>
<a name="37518"></a>
A method invocation expression is used to invoke a class or instance method.
<p><ul><pre>
<i>MethodInvocation:<br>
</i> <i>MethodName</i><code> ( </code><i>ArgumentList</i><sub><i>opt</i></sub><code> )<br>
</code> <i>Primary</i><code> . </code><i>Identifier</i><code> ( </code><i>ArgumentList</i><sub><i>opt</i></sub><code> )<br>
super . </code><i>Identifier</i><code> ( </code><i>ArgumentList</i><sub><i>opt</i></sub><code> )
</code></pre></ul><a name="8506"></a>
The definition of <i>ArgumentList</i> from <a href="15.doc.html#41147">§15.8</a> is repeated here for convenience:
<p><ul><pre>
<i>ArgumentList:<br>
</i> <i>Expression<br>
</i> <i>ArgumentList</i><code> , </code><i>Expression
</i></pre></ul><a name="228339"></a>
Resolving a method name at compile time is more complicated than resolving a field name because of the possibility of method overloading. Invoking a method at run time is also more complicated than accessing a field because of the possibility of instance method overriding.<p>
<a name="38751"></a>
Determining the method that will be invoked by a method invocation expression involves several steps. The following three sections describe the compile-time processing of a method invocation; the determination of the type of the method invocation expression is described in <a href="15.doc.html#23617">§15.11.3</a>.<p>
<a name="21692"></a>
<h3>15.11.1 Compile-Time Step 1: Determine Class or Interface to Search</h3>
<a name="37532"></a>
The first step in processing a method invocation at compile time is to figure out
the name of the method to be invoked and which class or interface to check for
definitions of methods of that name. There are several cases to consider, depending
on the form that precedes the left parenthesis, as follows:
<p><ul><a name="37552"></a>
<li>If the form is <i>MethodName</i>, then there are three subcases:
<ul>
<a name="37575"></a>
<li>If it is a simple name, that is, just an <i>Identifier</i>, then the name of the method is the <i>Identifier</i> and the class or interface to search is the one whose declaration contains the method invocation.
<a name="37556"></a>
<li>If it is a qualified name of the form <i>TypeName</i> <code>.</code> <i>Identifier</i>, then the name of the method is the <i>Identifier</i> and the class to search is the one named by the <i>TypeName</i>. If <i>TypeName</i> is the name of an interface rather than a class, then a compile-time error occurs, because this form can invoke only <code>static</code> methods and interfaces have no <code>static</code> methods.
<a name="37591"></a>
<li>In all other cases, the qualified name has the form <i>FieldName</i> <code>.</code> <i>Identifier</i>; then the name of the method is the <i>Identifier</i> and the class or interface to search is the declared type of the field named by the <i>FieldName</i>.
</ul>
<a name="37589"></a>
<li>If the form is <i>Primary</i> <code>.</code> <i>Identifier</i>, then the name of the method is the <i>Identifier</i>  and the class or interface to be searched is the type of the <i>Primary</i> expression.
<a name="37600"></a>
<li>If the form is <code>super</code> <code>.</code> <i>Identifier</i>, then the name of the method is the <i>Identifier</i> and the class to be searched is the superclass of the class whose declaration contains the method invocation. A compile-time error occurs if such a method invocation occurs in an interface, or in the class <code>Object</code>, or in a <code>static</code> method, a static initializer, or the initializer for a <code>static</code> variable. It follows that a method invocation of this form may appear only in a class other than <code>Object</code>, and only in the body of an instance method, the body of a constructor, or an initializer for an instance variable.
</ul><a name="21693"></a>
<h3>15.11.2 Compile-Time Step 2: Determine Method Signature</h3>
<a name="19915"></a>
The second step searches the class or interface determined in the previous step for
method declarations. This step uses the name of the method and the types of the
argument expressions to locate method declarations that are both <i>applicable</i> and
<i>accessible</i>, that is, declarations that can be correctly invoked on the given arguments.
There may be more than one such method declaration, in which case the
<i>most specific</i> one is chosen. The descriptor (signature plus return type) of the most
specific method declaration is one used at run time to do the method dispatch.
<p><a name="18427"></a>
<h4>15.11.2.1 Find Methods that are Applicable and Accessible</h4>
<a name="21818"></a>
A method declaration is <i>applicable</i> to a method invocation if and only if both of
the following are true:
<p><ul><a name="37650"></a>
<li>The number of parameters in the method declaration equals the number of argument  expressions in the method invocation.
<a name="37653"></a>
<li>The type of each actual argument can be converted by method invocation conversion <a href="5.doc.html#12687">(§5.3)</a> to the type of the corresponding parameter. Method invocation conversion is the same as assignment conversion <a href="5.doc.html#170768">(§5.2)</a>, except that constants of type <code>int</code> are never implicitly narrowed to <code>byte</code>, <code>short</code>, or <code>char</code>.
</ul><a name="21702"></a>
The class or interface determined by the process described in <a href="15.doc.html#21692">§15.11.1</a> is searched for all method declarations applicable to this method invocation; method definitions inherited from superclasses and superinterfaces are included in this search.<p>
<a name="37690"></a>
Whether a method declaration is <i>accessible</i> to a method invocation depends on the access modifier (<code>public</code>, none, <code>protected</code>, or <code>private</code>) in the method declaration and on where the method invocation appears.<p>
<a name="37675"></a>
If the class or interface has no method declaration that is both applicable and accessible, then a compile-time error occurs.<p>
<a name="37720"></a>
In the example program:<p>
<pre><a name="37706"></a>
public class Doubler {
<a name="37707"></a> static int two() { return two(1); }
<a name="37708"></a> private static int two(int i) { return 2*i; }
<a name="37709"></a>}
<a name="37710"></a>
class Test extends Doubler {
<a name="37733"></a> public static long two(long j) {return j+j; }
<a name="37711"></a>
public static void main(String[] args) {
<a name="37712"></a> System.out.println(two(3));
<a name="37713"></a> System.out.println(Doubler.two(3)); // compile-time error
<a name="37714"></a> }
<a name="37715"></a>}
</pre><a name="37704"></a>
for the method invocation <code>two(1)</code> within class <code>Doubler</code>, there are two accessible
methods named <code>two</code>, but only the second one is applicable, and so that is the one
invoked at run time. For the method invocation <code>two(3)</code> within class <code>Test</code>, there
are two applicable methods, but only the one in class <code>Test</code> is accessible, and so
that is the one to be invoked at run time (the argument <code>3</code> is converted to type
<code>long</code>). For the method invocation <code>Doubler.two(3)</code>, the class <code>Doubler</code>, not class
<code>Test</code>, is searched for methods named <code>two</code>; the only applicable method is not
accessible, and so this method invocation causes a compile-time error.
<p><a name="21942"></a>
Another example is:<p>
<pre><a name="21943"></a>
class ColoredPoint {
<a name="21949"></a> int x, y;
<a name="21950"></a> byte color;
<a name="21953"></a> void setColor(byte color) { this.color = color; }
<a name="21954"></a>}
<a name="21955"></a>
class Test {
<a name="21956"></a> public static void main(String[] args) {
<a name="21957"></a> ColoredPoint cp = new ColoredPoint();
<a name="21958"></a> byte color = 37;
<a name="21959"></a> cp.setColor(color);
<a name="21960"></a> cp.setColor(37); // compile-time error
<a name="21961"></a> }
<a name="21962"></a>}
</pre><a name="21881"></a>
Here, a compile-time error occurs for the second invocation of <code>setColor</code>, because
no applicable method can be found at compile time. The type of the literal <code>37</code> is
<code>int</code>, and <code>int</code> cannot be converted to <code>byte</code> by method invocation conversion.
Assignment conversion, which is used in the initialization of the variable <code>color</code>,
performs an implicit conversion of the constant from type <code>int</code> to <code>byte</code>, which is
permitted because the value <code>37</code> is small enough to be represented in type <code>byte</code>; but
such a conversion is not allowed for method invocation conversion.
<p><a name="21968"></a>
If the method <code>setColor</code> had, however, been declared to take an <code>int</code> instead of a <code>byte</code>, then both method invocations would be correct; the first invocation would be allowed because method invocation conversion does permit a widening conversion from <code>byte</code> to <code>int</code>. However, a narrowing cast would then be required in the body of <code>setColor</code>:<p>
<pre><a name="21973"></a> void setColor(int color) { this.color = (byte)color; }
</pre><a name="18428"></a>
<h4>15.11.2.2 Choose the Most Specific Method</h4>
<a name="21703"></a>
If more than one method is both accessible and applica
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -