📄 8.doc.html
字号:
<h4>8.3.1.3 transient Fields</h4>
<a name="37020"></a>
Variables may be marked <code>transient</code> to indicate that they are not part of the persistent
state of an object. If an instance of the class <code>Point</code>:
<p><pre><a name="14770"></a>
class Point {
<a name="14771"></a> int x, y;
<a name="14772"></a> transient float rho, theta;
<a name="14773"></a>}
</pre><a name="14775"></a>
were saved to persistent storage by a system service, then only the fields <code>x</code> and <code>y</code>
would be saved. This specification does not yet specify details of such services;
we intend to provide them in a future version of this specification.
<p><a name="36930"></a>
<h4>8.3.1.4 volatile Fields</h4>
<a name="37715"></a>
As described in <a href="17.doc.html#26250">§17</a>, the Java language allows threads that access shared variables
to keep private working copies of the variables; this allows a more efficient implementation
of multiple threads. These working copies need be reconciled with the
master copies in the shared main memory only at prescribed synchronization
points, namely when objects are locked or unlocked. As a rule, to ensure that
shared variables are consistently and reliably updated, a thread should ensure that
it has exclusive use of such variables by obtaining a lock that, conventionally,
enforces mutual exclusion for those shared variables.
<p><a name="37727"></a>
Java provides a second mechanism that is more convenient for some purposes: a field may be declared <code>volatile</code>, in which case a thread must reconcile its working copy of the field with the master copy every time it accesses the variable. Moreover, operations on the master copies of one or more volatile variables on behalf of a thread are performed by the main memory in exactly the order that the thread requested.<p>
<a name="14790"></a>
If, in the following example, one thread repeatedly calls the method <code>one</code> (but no more than <code>Integer.MAX_VALUE</code> <a href="javalang.doc6.html#2391">(§20.7.2)</a> times in all), and another thread repeatedly calls the method <code>two</code>:<p>
<pre><a name="14792"></a>
class Test {
<br><a name="14793"></a> static int i = 0, j = 0;
<br><a name="14794"></a>
static void one() { i++; j++; }
<a name="14796"></a>
static void two() {
<a name="14797"></a> System.out.println("i=" + i + " j=" + j);
<a name="14801"></a> }
<br><a name="14802"></a>}
</pre><a name="14803"></a>
then method <code>two</code> could occasionally print a value for <code>j</code> that is greater than the
value of <code>i</code>, because the example includes no synchronization and, under the rules
explained in <a href="17.doc.html#26250">§17</a>, the shared values of <code>i</code> and <code>j</code> might be updated out of order.
<p><a name="37738"></a>
One way to prevent this out-or-order behavior would be to declare methods <code>one</code> and <code>two</code> to be <code>synchronized</code> <a href="8.doc.html#55408">(§8.4.3.5)</a>:<p>
<pre><a name="37768"></a>
class Test {
<br><a name="37769"></a> static int i = 0, j = 0;
<br><a name="37770"></a>
static synchronized void one() { i++; j++; }
<a name="37771"></a>
static synchronized void two() {
<a name="37772"></a> System.out.println("i=" + i + " j=" + j);
<a name="37773"></a> }
<br><a name="37774"></a>}
</pre><a name="37777"></a>
This prevents method <code>one</code> and method <code>two</code> from being executed concurrently, and
furthermore guarantees that the shared values of <code>i</code> and <code>j</code> are both updated before
method <code>one</code> returns. Therefore method <code>two</code> never observes a value for <code>j</code> greater
than that for <code>i</code>; indeed, it always observes the same value for <code>i</code> and <code>j</code>.
<p><a name="37789"></a>
Another approach would be to declare <code>i</code> and <code>j</code> to be <code>volatile</code>:<p>
<pre><a name="37793"></a>
class Test {
<br><a name="37794"></a> static volatile int i = 0, j = 0;
<br><a name="37795"></a>
static void one() { i++; j++; }
<a name="37796"></a>
static void two() {
<a name="37797"></a> System.out.println("i=" + i + " j=" + j);
<a name="37798"></a> }
<br><a name="37799"></a>}
</pre><a name="37800"></a>
This allows method <code>one</code> and method <code>two</code> to be executed concurrently, but guarantees
that accesses to the shared values for <code>i</code> and <code>j</code> occur exactly as many times,
and in exactly the same order, as they appear to occur during execution of the program
text by each thread. Therefore, method <code>two</code> never observes a value for <code>j</code>
greater than that for <code>i</code>, because each update to <code>i</code> must be reflected in the shared
value for <code>i</code> before the update to <code>j</code> occurs. It is possible, however, that any given
invocation of method <code>two</code> might observe a value for <code>j</code> that is much greater than the
value observed for <code>i</code>, because method <code>one</code> might be executed many times between
the moment when method <code>two</code> fetches the value of <code>i</code> and the moment when
method <code>two</code> fetches the value of <code>j</code>.
<p><a name="14791"></a>
See <a href="17.doc.html#26250">§17</a> for more discussion and examples.<p>
<a name="24509"></a>
A compile-time error occurs if a <code>final</code> variable is also declared <code>volatile</code>.<p>
<a name="24510"></a>
<h3>8.3.2 Initialization of Fields</h3>
<a name="41082"></a>
If a field declarator contains a <i>variable initializer</i>, then it has the semantics of an
assignment <a href="15.doc.html#5281">(§15.25)</a> to the declared variable, and:
<p><ul><a name="37635"></a>
<li>If the declarator is for a class variable (that is, a <code>static</code> field), then the variable initializer is evaluated and the assignment performed exactly once, when the class is initialized <a href="12.doc.html#44557">(§12.4)</a>.
<a name="37639"></a>
<li>If the declarator is for an instance variable (that is, a field that is not <code>static</code>), then the variable initializer is evaluated and the assignment performed each time an instance of the class is created <a href="12.doc.html#44670">(§12.5)</a>.
</ul><a name="38002"></a>
The example:<p>
<pre><a name="30354"></a>
class Point {
<a name="30355"></a> int x = 1, y = 5;
<a name="30356"></a>}
<br><a name="30357"></a>class Test {
<a name="30358"></a> public static void main(String[] args) {
<a name="30359"></a> Point p = new Point();
<a name="30360"></a> System.out.println(p.x + ", " + p.y);
<a name="30361"></a> }
<a name="30362"></a>}
</pre><a name="30363"></a>
produces the output:
<p><pre><a name="30377"></a>1, 5
</pre><a name="30378"></a>
because the assignments to <code>x</code> and <code>y</code> occur whenever a new <code>Point</code> is created.
<p><a name="30370"></a>
Variable initializers are also used in local variable declaration statements <a href="14.doc.html#5920">(§14.3)</a>, where the initializer is evaluated and the assignment performed each time the local variable declaration statement is executed.<p>
<a name="38006"></a>
It is a compile-time error if the evaluation of a variable initializer for a field of a class (or interface) can complete abruptly with a checked exception <a href="11.doc.html#44121">(§11.2)</a>.<p>
<a name="38010"></a>
<h4>8.3.2.1 Initializers for Class Variables</h4>
<a name="229741"></a>
A compile-time error occurs if an initialization expression for a class variable contains
a use by a simple name of that class variable or of another class variable
whose declaration occurs to its right (that is, textually later) in the same class.
Thus:
<p><pre><a name="229742"></a>
class Test {
<a name="229743"></a> static float f = j; // compile-time error: forward reference
<a name="229744"></a> static int j = 1;
<a name="229745"></a> static int k = k+1; // compile-time error: forward reference
<a name="229746"></a>}
</pre><a name="229747"></a>
causes two compile-time errors, because <code>j</code> is referred to in the initialization of <code>f</code>
before <code>j</code> is declared and because the initialization of <code>k</code> refers to <code>k</code> itself.
<p><a name="37971"></a>
If a reference by simple name to any instance variable occurs in an initialization expression for a class variable, then a compile-time error occurs.<p>
<a name="37934"></a>
If the keyword <code>this</code> <a href="15.doc.html#31980">(§15.7.2)</a> or the keyword <code>super</code> (<a href="15.doc.html#20860">§15.10.2</a>, <a href="15.doc.html#20448">§15.11</a>) occurs in an initialization expression for a class variable, then a compile-time error occurs.<p>
<a name="229548"></a>
(One subtlety here is that, at run time, <code>static</code> variables that are <code>final</code> and that are initialized with compile-time constant values are initialized first. This also applies to such fields in interfaces <a href="9.doc.html#40720">(§9.3.1)</a>. These variables are "constants" that will never be observed to have their default initial values <a href="4.doc.html#10931">(§4.5.4)</a>, even by devious programs. See <a href="12.doc.html#44630">§12.4.2</a> and <a href="13.doc.html#45139">§13.4.8</a> for more discussion.)<p>
<a name="38013"></a>
<h4>8.3.2.2 Initializers for Instance Variables</h4>
<a name="30374"></a>
A compile-time error occurs if an initialization expression for an instance variable
contains a use by a simple name of that instance variable or of another instance
variable whose declaration occurs to its right (that is, textually later) in the same
class. Thus:
<p><pre><a name="27881"></a>
class Test {
<a name="27882"></a> float f = j;
<a name="27883"></a> int j = 1;
<a name="37876"></a> int k = k+1;
<a name="27884"></a>}
</pre><a name="27885"></a>
causes two compile-time errors, because <code>j</code> is referred to in the initialization of <code>f</code>
before <code>j</code> is declared and because the initialization of <code>k</code> refers to <code>k</code> itself.
<p><a name="37982"></a>
Initialization expressions for instance variables may use the simple name of any <code>static</code> variable declared in or inherited by the class, even one whose declaration occurs textually later. Thus the example:<p>
<pre><a name="37983"></a>
class Test {
<a name="37984"></a> float f = j;
<a name="37985"></a> static int j = 1;
<a name="37987"></a>}
</pre><a name="37988"></a>
compiles without error; it initializes <code>j</code> to <code>1</code> when class <code>Test</code> is initialized, and initializes
<code>f</code> to the current value of <code>j</code> every time an instance of class <code>Test</code> is created.
<p><a name="40409"></a>
Initialization expressions for instance variables are permitted to refer to the current object <code>this</code> <a href="15.doc.html#31980">(§15.7.2)</a> and to use the keyword <code>super</code> (<a href="15.doc.html#20860">§15.10.2</a>, <a href="15.doc.html#20448">§15.11</a>).<p>
<a name="40425"></a>
<h3>8.3.3 Examples of Field Declarations</h3>
<a name="40426"></a>
The following examples illustrate some (possibly subtle) points about field declarations.
<p><a name="40428"></a>
<h4>8.3.3.1 Example: Hiding of Class Variables</h4>
<a name="40429"></a>
The example:
<p><pre><a name="40430"></a>
class Point {
<a name="40431"></a> static int x = 2;
<a name="40432"></a>}
<br><a name="40433"></a>
class Test extends Point {
<a name="40434"></a> static double x = 4.7;
<a name="40435"></a> public static void main(String[] args) {<br>
new Test().printX();
<a name="229781"></a> }
<a name="229782"></a> void printX() {
<a name="40436"></a> System.out.println(x + " " + super.x);
<a name="40437"></a> }
<a name="40438"></a>}
</pre><a name="40439"></a>
produces the output:
<p><pre><a name="40440"></a>4.7 2
</pre><a name="40441"></a>
because the declaration of <code>x</code> in class <code>Test</code> hides the definition of <code>x</code> in class <code>Point</code>,
so class <code>Test</code> does not inherit the field <code>x</code> from its superclass <code>Point</code>. Within the
declaration of class <code>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -