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

📄 13.doc.html

📁 java语言规范
💻 HTML
📖 第 1 页 / 共 4 页
字号:
<a name="45132"></a>	int h = 0;
<a name="45133"></a>}
</pre><a name="45134"></a>
recompiling <code>Hyper</code> and <code>Super</code>, and executing the resulting new binaries with the 
old binary of <code>Test</code> produces the output:
<p><pre><a name="45135"></a>hyper
</pre><a name="45136"></a>
The field <code>h</code> of <code>Hyper</code> is output by the original binary of <code>main</code> no matter what type 
field <code>h</code> is declared in <code>Super</code>. While this may seem surprising at first, it serves to 
reduce the number of incompatibilities that occur at run time. (In an ideal world, 
all source files that needed recompilation would be recompiled whenever any one 
of them changed, eliminating such surprises. But such a mass recompilation is 
often impractical or impossible, especially in the Internet. And, as was previously 
noted, such recompilation would sometimes require further changes to the source 
code.)
<p><a name="45137"></a>
Deleting a field from a class will break compatibility with any pre-existing binaries that reference this field, and a <code>NoSuchFieldError</code> will be thrown when such a reference from a pre-existing binary is linked. Only <code>private</code> fields may be safely deleted from a widely distributed class.<p>
<a name="45139"></a>
<h3>13.4.8    <code>final</code> Fields and Constants</h3>
<a name="45140"></a>
If a field that was not <code>final</code> is changed to be <code>final</code>, then it can break compatibility
with pre-existing binaries that attempt to assign new values to the field. For 
example, if the program:
<p><pre><a name="45141"></a>class Super { static char s; }
</pre><pre><a name="45142"></a>
class Test extends Super {
<a name="45143"></a>	public static void main(String[] args) {
<a name="45144"></a>		s = 'a';
<a name="45145"></a>		System.out.println(s);
<a name="45146"></a>	}
<a name="45147"></a>}
</pre><a name="45148"></a>
is compiled and executed, it produces the output:
<p><pre><a name="45149"></a>a
</pre><a name="47429"></a>
Suppose that a new version of class <code>Super</code> is produced:
<p><pre><a name="47321"></a>class Super { static char s; }
</pre><a name="45152"></a>
If <code>Super</code> is recompiled but not <code>Test</code>, then running the new binary with the existing
binary of <code>Test</code> results in a <code>IncompatibleClassChangeError</code>. (In certain 
early implementations of Java this example would run without error, because of a 
flaw in the implementation.)
<p><a name="45153"></a>
We call a field that is <code>static</code>, <code>final</code>, and initialized with a compile-time constant expression a <i>primitive</i> <i>constant</i>. Note that all fields in interfaces are implicitly <code>static</code> and <code>final</code>, and they are often, but not always, constants.<p>
<a name="45154"></a>
If a field is not a primitive constant, then deleting the keyword <code>final</code> or changing the value to which the field is initialized does not break compatibility with existing binaries.<p>
<a name="45155"></a>
If a field is a primitive constant, then deleting the keyword <code>final</code> or changing its value will not break compatibility with pre-existing binaries by causing them not to run, but they will not see any new value for the constant unless they are recompiled. If the example:<p>
<pre><a name="45156"></a>class Flags { final static boolean debug = true; }
</pre><pre><a name="45157"></a>
class Test {
<a name="45158"></a>	public static void main(String[] args) {
<a name="45159"></a>		if (Flags.debug)
<a name="45160"></a>			System.out.println("debug is true");
<a name="45161"></a>	}
<a name="45162"></a>}
</pre><a name="45163"></a>
is compiled and executed, it produces the output:
<p><pre><a name="45164"></a>debug is true
</pre><a name="45165"></a>
Suppose that a new version of class <code>Flags</code> is produced:
<p><pre><a name="45166"></a>class Flags { final static boolean debug = false; }
</pre><a name="45167"></a>
If <code>Flags</code> is recompiled but not <code>Test</code>, then running the new binary with the existing
binary of <code>Test</code> produces the output:
<p><pre><a name="45168"></a>debug is true
</pre><a name="45169"></a>
because the value of <code>debug</code> was a compile-time primitive constant, and could have 
been used in compiling <code>Test</code> without making a reference to the class <code>Flags</code>.
<p><a name="47322"></a>
This result is a side-effect of the decision to support conditional compilation, as discussed at the end of <a href="14.doc.html#236365">&#167;14.19</a>.<p>
<a name="47435"></a>
This behavior would not change if <code>Flags</code> were changed to be an interface, as in the modified example:<p>
<pre><a name="45170"></a>interface Flags { boolean debug = true; }
<a name="45171"></a>class Test {
<a name="45172"></a>	public static void main(String[] args) {
<a name="45173"></a>		if (Flags.debug)
<a name="45174"></a>			System.out.println("debug is true");
<a name="45175"></a>	}
<a name="45176"></a>}
</pre><a name="45177"></a>
(One reason for requiring inlining of primitive constants is that Java <code>switch</code> statements
require constants on each <code>case</code>, and no two such constant values may be 
the same. Java checks for duplicate constant values in a <code>switch</code> statement at compile
time; the <code>class</code> file format does not do symbolic linkage of <code>case</code> values.)
<p><a name="45178"></a>
The best way to avoid problems with "inconstant constants" in widely-distributed code is to declare as primitive constants only values which truly are unlikely ever to change. Many primitive constants in interfaces are small integer values replacing enumerated types, which Java does not support; these small values can be chosen arbitrarily, and should not need to be changed. Other than for true mathematical constants, we recommend that Java code make very sparing use of class variables that are declared <code>static</code> and <code>final</code>. If the read-only nature of <code>final</code> is required, a better choice is to declare a <code>private</code> <code>static</code> variable and a suitable accessor method to get its value. Thus we recommend:<p>
<pre><a name="45179"></a>private static int N;
<a name="45180"></a>public static int getN() { return N; }
</pre><a name="45181"></a>
rather than:
<p><pre><a name="45182"></a>public static final int N = ...;
</pre><a name="45183"></a>
There is no problem with:
<p><pre><a name="45184"></a>public static int N = ...;
</pre><a name="45185"></a>
if <code>N</code> need not be read-only. We also recommend, as a general rule, that only truly 
constant values be declared in interfaces. We note, but do not recommend, that if a 
field of primitive type of an interface may change, its value may be expressed idiomatically
as in:
<p><pre><a name="45186"></a>
interface Flags {
<a name="45187"></a>	boolean debug = new Boolean(true).booleanValue();
<a name="45188"></a>}
</pre><a name="47644"></a>
insuring that this value is not a constant. Similar idioms exist for the other primitive
types.
<p><a name="47645"></a>
One other thing to note is that <code>static</code> <code>final</code> fields that have constant values (whether of primitive or <code>String</code> type) must never appear to have the default initial value for their type <a href="4.doc.html#10931">(&#167;4.5.4)</a>. This means that all such fields appear to be initialized first during class initialization (<a href="8.doc.html#38010">&#167;8.3.2.1</a>, <a href="9.doc.html#40720">&#167;9.3.1</a>, <a href="12.doc.html#44630">&#167;12.4.2</a>).<p>
<a name="45190"></a>
<h3>13.4.9    <code>static</code> Fields</h3>
<a name="45191"></a>
If a field that is not declared <code>private</code> was not declared <code>static</code> and is changed to 
be declared <code>static</code>, or vice versa, then a linkage time error, specifically an 
<code>IncompatibleClassChangeError</code>, will result if the field is used by a preexisting 
binary which expected a field of the other kind. Such changes are not recommended
in code that has been widely distributed.
<p><a name="45192"></a>
<h3>13.4.10    <code>transient</code> Fields</h3>
<a name="45193"></a>
Adding or deleting a <code>transient</code> modifier of a field does not break compatibility 
with pre-existing binaries.
<p><a name="45194"></a>
<h3>13.4.11    <code>volatile</code> Fields</h3>
<a name="45195"></a>
If a field that is not declared <code>private</code> was not declared <code>volatile</code> and is changed 
to be declared <code>volatile</code>, or vice versa, then a linkage time error, specifically an 
<code>IncompatibleClassChangeError</code>, may result if the field is used by a preexisting 
binary that expected a field of the opposite volatility. Such changes are not recommended
in code that has been widely distributed.
<p><a name="45197"></a>
<h3>13.4.12    Method and Constructor Declarations</h3>
<a name="45198"></a>
Adding a method or constructor declaration to a class will not break compatibility 
with any pre-existing binaries, even in the case where a type could no longer be 
recompiled because a method invocation previously referenced a method of a 
superclass with an incompatible type. The previously compiled class with such a 
reference will continue to reference the method declared in a superclass.
<p><a name="45199"></a>
Deleting a method or constructor from a class will break compatibility with any pre-existing binary that referenced this method or constructor; a <code>NoSuchMethodError</code> &#32;will be thrown when such a reference from a pre-existing binary is linked. Only <code>private</code> methods or constructors may be safely deleted from a widely distributed class.<p>
<a name="45200"></a>
If the source code for a class contains no declared constructors, the Java compiler automatically supplies a constructor with no parameters. Adding one or more constructor declarations to the source code of such a class will prevent this default constructor from being supplied automatically, effectively deleting a constructor, unless one of the new constructors also has no parameters, thus replacing the default constructor. The automatically supplied constructor with no parameters is given the same access modifier as the class of its declaration, so any replacement should have as much or more access if compatibility with pre-existing binaries is to be preserved.<p>
<a name="45202"></a>
<h3>13.4.13    Method and Constructor Parameters</h3>
<a name="45203"></a>
Changing the name of a formal parameter of a method or constructor does not 
impact pre-existing binaries. Changing the name of a method, the type of a formal 
parameter to a method or constructor, or adding a parameter to or deleting a 
parameter from a method or constructor declaration creates a method or constructor
with a new signature, and has the combined effect of deleting the method or 
constructor with the old signature and adding a method or constructor with the 
new signature (see <a href="13.doc.html#45197">&#167;13.4.12</a>).
<p><a name="45208"></a>
<h3>13.4.14    Method Result Type</h3>
<a name="45209"></a>
Changing the result type of a method, replacing a result type with <code>void</code>, or replacing
<code>void</code> with a result type has the combined effect of deleting the old method or 
constructor and adding a new method or constructor with the new result type or 
newly <code>void</code> result (see <a href="13.doc.html#45197">&#167;13.4.12</a>).
<p><a name="45214"></a>
<h3>13.4.15    <code>abstract</code> Methods</h3>
<a name="45215"></a>
Changing a method that is declared <code>abstract</code> to no longer be declared <code>abstract</code> 
does not break compatibility with pre-existing binaries.
<p><a name="45216"></a>
Changing a method that is not declared <code>abstract</code> to be declared <code>abstract</code> will break compatibility with pre-existing binaries that previously invoked the method, causing an <code>AbstractMethodError</code>. If the example program:<p>
<pre><a name="45217"></a>
class Super { void out() { System.out.println("Out"); } }
<a name="45220"></a>
class Test extends Super {
<a name="45221"></a>	public static void main(String[] args) {
<a name="45222"></a>		Test t = new Test();
<a name="45223"></a>		System.out.println("Way ");
<a name="45224"></a>		t.out();
<a name="45225"></a>	}
<a name="45226"></a>}
</pre><a name="45227"></a>
is compiled and executed, it produces the output:
<p><pre><a name="45228"></a>
Way
<a name="45229"></a>Out
</pre><a name="45230"></a>
Suppose that a new version of class <code>Super</code> is produced:
<p><pre><a name="45231"></a>
abstract class Super {
<a name="45232"></a>	abstract void out();
<a name="45233"></a>}
</pre><a name="45234"></a>
If <code>Super</code> is recompiled but not <code>Test</code>, then running the new binary with the existing
binary of <code>Test</code> results in a <code>AbstractMethodError</code>, because class <code>Test</code> has no 
implementation of the method <code>out</code>, and is therefore is (or should be) abstract. (An 
early version of Java incorrectly produced the output:
<p><pre><a name="45235"></a>Way
</pre><a name="45236"></a>
before encountering an <code>AbstractMethodError</code> while invoking the method <code>out</code>, 
incorrectly allowing the class <code>Test</code> to be prepared even though it has an <code>abstract</code> 
method and is not declared <code>abstract</code>.)
<p><a name="45238"></a>
<h3>13.4.16    <code>final</code> Methods</h3>
<a name="45239"></a>
Changing an instance method that is not <code>final</code> to be <code>final</code> may break compatibility
with existing binaries that depend on the ability to override the method. If 
the test program:
<p><pre><a name="45240"></a>class Super { void out() { System.out.println("out"); } }
<a name="45241"></a>class Test extends Super {
</pre><pre><a name="45242"></a>
	public static void main(String[] args) {
<a name="45243"></a>		Test t = new Test();
<a name="45244"></a>		t.out();
<a name="45245"></a>	}
<a name="45246"></a>	void out() { super.out(); }
<a name="45247"></a>}
</pre><a name="45248"></a>
is compiled and executed, it produces the output:
<p><pre><a name="45249"></a>out
</pre><a name="45250"></a>
Suppose that a new version of class <code>Super</code> is produced:
<p><pre><a name="45251"></a>class Super { final void out() { System.out.println("!"); } }
</pre><a name="45252"></a>
If <code>Super</code> is recompiled but not <code>Test</code>, then running the new binary with the existing
binary of <code>Test</code> results in a <code>VerifyError</code> because the class <code>Test</code> improperly 
tries to override the instance method <code>out</code>.
<p><a name="45253"></a>

⌨️ 快捷键说明

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