⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 13.doc.html

📁 java语言规范
💻 HTML
📖 第 1 页 / 共 4 页
字号:
The assumed implementation determines that the class <code>Super</code> has two methods: 
the first is method <code>zero</code> inherited from class <code>Hyper</code>, and the second is the method 
<code>peek</code>. Any subclass of <code>Super</code> would also have these same two methods in the first 
two entries of its method table. (Actually, all these methods would be preceded in 
the method tables by all the methods inherited from class <code>Object</code> but, to simplify 
the discussion, we ignore that here.) For the method invocation <code>as.zero(as)</code>, the 
compiler specifies that the first method of the method table should be invoked; this 
is always correct if type safety is preserved.
<p><a name="45026"></a>
If the compiled code is then executed, it prints something like:<p>
<pre><a name="45027"></a>
Super@ee300858
<a name="45028"></a>0
</pre><a name="45029"></a>
which is the correct output. But if a new version of <code>Super</code> is compiled, which is 
the same except for the <code>extends</code> clause:
<p><pre><a name="47244"></a>class Super { int peek(int i) { return i; }  }
</pre><a name="45031"></a>
then the first method in the method table for <code>Super</code> will now be <code>peek</code>, not <code>zero</code>. 
Using the new binary code for <code>Super</code> with the old binary code for <code>Hyper</code> and 
<code>Test</code> will cause the method invocation <code>as.zero(as)</code> to dispatch to the method 
<code>peek</code> in <code>Super</code>, rather than the method <code>zero</code> in <code>Hyper</code>. This is a type violation, of 
course; the argument is of type <code>Super</code> but the parameter is of type <code>int</code>. With a few 
plausible assumptions about internal data representations and the consequences of 
the type violation, execution of this incorrect program might produce the output:
<p><pre><a name="45032"></a>
Super@ee300848
<a name="45033"></a>ee300848
</pre><a name="45034"></a>
A <code>poke</code> method, capable of altering any location in memory, could be concocted 
in a similar manner. This is left as an exercise for the reader.
<p><a name="45035"></a>
The lesson is that a implementation of Java that lacks a verifier or fails to use it will not maintain type safety and is, therefore, not a valid Java implementation. <p>
<a name="45037"></a>
<h3>13.4.5    Class Body and Member Declarations</h3>
<a name="45038"></a>
No incompatibility with pre-existing binaries is caused by adding a class member 
that has the same name (for fields) or same name, signature, and return type (for 
methods) as a member of a superclass or subclass. References to the original field 
or method were resolved at compile time to a symbolic reference containing the 
name of the class in which they were declared. This makes compiled Java code 
more robust against changes than it might otherwise be. No error occurs even if 
the set of classes being linked would encounter a compile-time error. As an example,
if the program:
<p><pre><a name="45039"></a>class Hyper { String h = "Hyper"; }
<a name="45040"></a>class Super extends Hyper { }
<a name="45041"></a>class Test extends Super {
<a name="45042"></a>	public static void main(String[] args) {
<a name="45043"></a>		String s = new Test().h;
<a name="45044"></a>		System.out.println(s);
<a name="45045"></a>	}
<a name="45046"></a>}
</pre><a name="45047"></a>
is compiled and executed, it produces the output:
<p><pre><a name="45048"></a>Hyper
</pre><a name="45049"></a>
Suppose that a new version of class <code>Super</code> is then compiled:
<p><pre><a name="45050"></a>class Super extends Hyper { char h = 'h'; }
</pre><a name="45051"></a>
If the resulting binary is used with the existing binaries for <code>Hyper</code> and <code>Test</code>, then 
the output is still:
<p><pre><a name="45052"></a>Hyper
</pre><a name="45053"></a>
even though compiling the source for these binaries:
<p><pre><a name="45054"></a>class Hyper { String h = "Hyper"; }
<a name="45055"></a>class Super extends Hyper { char h = 'h'; }
<a name="45056"></a>class Test extends Super {
<a name="45057"></a>	public static void main(String[] args) {
<a name="45058"></a>		String s = new Test().h;
<a name="45059"></a>		System.out.println(s);
<a name="45060"></a>	}
<a name="45061"></a>}
</pre><a name="45062"></a>
would result in a compile-time error, because the <code>h</code> in the source code for <code>main</code> 
would now be construed as referring to the <code>char</code> field declared in <code>Super</code>, and a 
<code>char</code> value can't be assigned to a <code>String</code>.
<p><a name="45063"></a>
Deleting a class member or constructor that is not declared <code>private</code> may cause a linkage error if the member or constructor is used by a pre-existing binary, even if the member was an instance method that was overriding a superclass method. This is because, during resolution, the linker looks only in the class that was identified at compile time. Thus, if the program:<p>
<pre><a name="45064"></a>
class Hyper {
<a name="45065"></a>	void hello() { System.out.println("hello from Hyper"); }
<a name="45066"></a>}
<a name="45067"></a>
class Super extends Hyper {
<a name="45068"></a>	void hello() { System.out.println("hello from Super"); }
<a name="45069"></a>}
<a name="45070"></a>
class Test {
<a name="45071"></a>	public static void main(String[] args) {
<a name="45072"></a>		new Super().hello();
<a name="45073"></a>	}
<a name="45074"></a>}
</pre><a name="45075"></a>
is compiled and executed, it produces the output:
<p><pre><a name="45076"></a>hello from Super
</pre><a name="45077"></a>
Suppose that a new version of class <code>Super</code> is produced:
<p><pre><a name="45078"></a>class Super extends Hyper { }
</pre><a name="45079"></a>
If <code>Super</code> and <code>Hyper</code> are recompiled but not <code>Test</code>, then a <code>NoSuchMethodError</code> 
will result at link time, because the method <code>hello</code> is no longer declared in class 
<code>Super</code>.
<p><a name="45080"></a>
To preserve binary compatibility, methods should not be deleted; instead, "forwarding methods" should be used. In our example, replacing the declaration of <code>Super</code> with:<p>
<pre><a name="45081"></a>
class Super extends Hyper {
<a name="45082"></a>	void hello() { super.hello(); }
<a name="45083"></a>}
</pre><a name="45084"></a>
then recompiling <code>Super</code> and <code>Hyper</code> and executing these new binaries with the 
original binary for <code>Test</code>, produces the output:
<p><pre><a name="45085"></a>hello from Hyper
</pre><a name="45086"></a>
as might have naively been expected from the previous example.
<p><a name="45087"></a>
The <code>super</code> keyword can be used to access a method declared in a superclass, bypassing any methods declared in the current class. The expression:<p>
<pre><a name="45088"></a><code>super.</code><i>Identifier
</i></pre><a name="45089"></a>
is resolved, at compile time, to a method <i>M</i> declared in a particular superclass <i>S</i>. 
The method <i>M</i> must still be declared in that class at run time or a linkage error will 
result. If the method <i>M</i> is an instance method, then the method <i>MR</i> invoked at run 
time is the method with the same signature as <i>M</i> that is a member of the direct 
superclass of the class containing the expression involving <code>super</code>. Thus, if the 
program:
<p><pre><a name="45090"></a>
class Hyper {
<a name="45091"></a>	void hello() { System.out.println("hello from Hyper"); }
<a name="45092"></a>}
<a name="45093"></a>class Super extends Hyper { }
<a name="45094"></a>class Test extends Super {
<a name="45095"></a>
	public static void main(String[] args) {
<a name="45096"></a>		new Test().hello();
<a name="45097"></a>	}
<a name="45098"></a>
	void hello() {
<a name="45099"></a>		super.hello();
<a name="45100"></a>	}
<a name="45101"></a>}
</pre><a name="45102"></a>
is compiled and executed, it produces the output:
<p><pre><a name="45103"></a>hello from Hyper
</pre><a name="45104"></a>
Suppose that a new version of class <code>Super</code> is produced:
<p><pre><a name="45105"></a>
class Super extends Hyper {
<a name="45106"></a>	void hello() { System.out.println("hello from Super"); }
<a name="45107"></a>}
</pre><a name="45108"></a>
If <code>Super</code> and <code>Hyper</code> are recompiled but not <code>Test</code>, then running the new binaries 
with the existing binary of <code>Test</code> produces the output:
<p><pre><a name="45109"></a>hello from Super
</pre><a name="45110"></a>
as you might expect. (A flaw in some early versions of Java caused them to print:
<p><pre><a name="45111"></a>hello from Hyper
</pre><a name="45114"></a>
incorrectly.)
<p><a name="47259"></a>
<h3>13.4.6    Access to Members and Constructors</h3>
<a name="45115"></a>
Changing the declared access of a member or constructor to permit less access 
may break compatibility with pre-existing binaries, causing a linkage error to be 
thrown when these binaries are resolved. Less access is permitted if the access 
modifier is changed from default access to <code>private</code> access; from <code>protected</code> 
access to default or <code>private</code> access; or from <code>public</code> access to <code>protected</code>, 
default, or <code>private</code> access. Changing a member or constructor to permit less 
access is therefore not recommended for widely distributed classes.
<p><a name="45116"></a>
Perhaps surprisingly, Java is defined so that changing a member or constructor to be more accessible does not cause a linkage error when a subclass (already) defines a method to have less access. So, for example, if the package <code>points</code> defines the class <code>Point</code>:<p>
<pre><a name="45715"></a><code>package points;
</code></pre><pre><a name="45716"></a>
<code>public class Point {
</code><a name="45721"></a>	public int x, y;
<a name="45722"></a>	protected void print() {
<a name="45723"></a>		System.out.println("(" + x + "," + y + ")");
<a name="45724"></a>	}
<a name="45725"></a>}
</pre><a name="45726"></a>
used by the <code>Test</code> program:
<p><pre><a name="45727"></a>
class Test extends points.Point {
<a name="45733"></a>	protected void print() { System.out.println("Test"); }
<a name="45728"></a>	public static void main(String[] args) {
<a name="45730"></a>		Test t = new Test();
<a name="45729"></a>		t.print();
<a name="45731"></a>	}
<a name="45732"></a>}
</pre><a name="45734"></a>
then these classes compile and <code>Test</code> executes to produce the output:
<p><pre><a name="45735"></a>Test
</pre><a name="45736"></a>
If the method <code>print</code> in class <code>Point</code> is changed to be <code>public</code>, and then only the 
<code>Point</code> class is recompiled, and then executed with the previously existing binary 
for <code>Test</code> then no linkage error occurs, even though it is improper, at compile time, 
for a <code>public</code> method to be overridden by a <code>protected</code> method (as shown by the 
fact that the class <code>Test</code> could not be recompiled using this new <code>Point</code> class unless 
print were changed to be <code>public</code>.)
<p><a name="47725"></a>
Allowing superclasses to change <code>protected</code> methods to be <code>public</code> without breaking binaries of preexisting subclasses helps make Java binaries less fragile. The alternative, where such a change would cause a linkage error, would create additional binary incompatibilities with no apparent benefit.<p>
<a name="45118"></a>
<h3>13.4.7    Field Declarations</h3>
<a name="45119"></a>
Adding a field to a class will not break compatibility with any pre-existing binaries
that are not recompiled, even in the case where a class could no longer be 
recompiled because a field access previously referenced a field of a superclass 
with an incompatible type. The previously compiled class with such a reference 
will continue to reference the field declared in a superclass. Thus compiling and 
executing the code:
<p><pre><a name="45120"></a>class Hyper { String h = "hyper"; }
<a name="45121"></a>class Super extends Hyper { String s = "super"; }
<a name="45122"></a>class Test {
<a name="45123"></a>	public static void main(String[] args) {
<a name="45124"></a>		System.out.println(new Super().h);
<a name="45125"></a>	}
<a name="45126"></a>}
</pre><a name="45127"></a>
produces the output:
<p><pre><a name="45128"></a>hyper
</pre><a name="47307"></a>
Changing <code>Super</code> to be defined as:
<p><pre><a name="45130"></a>
class Super extends Hyper {
<a name="45131"></a>	String s = "super";

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -