📄 chap07.html
字号:
<P> </P>
<P> // This is the static initializer</P>
<P> static {</P>
<P> </P>
<P> size = 3 * (int) (Math.random() * 5.0);</P>
<P> }</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>All the class variable initializers and static initializers of a class are collected by the Java compiler and placed into one special method, the <I>class initialization method</I>. In the Java class file, the class initialization method is named "<FONT FACE="Courier New"><clinit</FONT>". Regular methods of a Java application cannot invoke a class initialization method. This kind of method can only be invoked by the Java Virtual Machine, which invokes it to set a class韘 static variables to their proper initial values.</P>
<P>Initialization of a class consists of two steps:</P>
<OL><LI>Initializing the class韘 direct superclass (if any), if the direct superclass hasn韙 already been initialized</P>
<LI>Executing the class韘 class initialization method, if it has one</OL>
<P>When initializing a class韘 direct superclass, the same two steps listed above must be followed. As a result, the first class that will be initialized will always be <FONT FACE="Courier New">Object</FONT>, then all the classes on down the inheritance hierarchy to the class being actively used. Superclasses will be initialized before subclasses.</P>
<P>Initialization of an interface does not require initialization of its superinterfaces. Initialization of an interface consists of only one step:</P>
<UL><LI> Executing the interface韘 class initialization method, if it has one</UL>
<P>The code of a <FONT FACE="Courier New"><clinit</FONT>()</FONT> method does not explicitly invoke a superclass韘 <FONT FACE="Courier New"><clinit</FONT>()</FONT> method. Before a Java Virtual Machine invokes the <FONT FACE="Courier New"><clinit</FONT>()</FONT> method of a class, therefore, it must make certain the <FONT FACE="Courier New"><clinit</FONT>()</FONT> methods of superclasses have been executed.</P>
<P>Java Virtual Machines must also make sure the initialization process is properly synchronized. If multiple threads need to initialize a class, only one thread should be allowed to perform the initialization while the other threads wait. After the active thread completes the initialization process, it must notify any waiting threads. See Chapter 20, "Thread Synchronization," for information about synchronization, wait and notify.</P>
<P><H4><EM>The Class Initialization Method</P></EM></H4>
<P>As mentioned above, Java compilers place the code for class variable initializers and static initializers into the <FONT FACE="Courier New"><clinit</FONT>()</FONT> method of the class file in the order in which they appear in the class declaration. For example, given this class:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// On CD-ROM in file classlife/ex1/Example1c.java
<P>class Example1c {</P>
<P> </P>
<P> static int width;</P>
<P> static int height = (int) (Math.random() * 2.0);</P>
<P> </P>
<P> // This is the static initializer</P>
<P> static {</P>
<P> </P>
<P> width = 3 * (int) (Math.random() * 5.0);</P>
<P> }</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>The Java compiler generates the following <FONT FACE="Courier New"><clinit</FONT>()</FONT> method:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// The code for height's class variable initializer begins here
<P> // Invoke Math.random(), which will push</P>
<P> // a double return value</P>
<P> 0 invokestatic #6 <Method double random()</FONT></P>
<P> 3 ldc2_w #8 <Double 2.0</FONT> // Push double constant 2.0</P>
<P> 6 dmul // Pop two doubles, multiply, push result</P>
<P> 7 d2i // Pop double, convert to int, push int</P>
<P> // Pop int, store into class variable</P>
<P> // height</P>
<P> 8 putstatic #5 <Field int height</FONT></P>
<P> </P>
<P>// The code for the static initializer begins here</P>
<P>11 iconst_3 // Push int constant 3</P>
<P> // Invoke Math.random(), which will push</P>
<P> // a double return value</P>
<P>12 invokestatic #6 <Method double random()</FONT></P>
<P>15 ldc2_w #10 <Double 5.0</FONT> // Push double constant 5.0</P>
<P>18 dmul // Pop two doubles, multiply, push result</P>
<P>19 d2i // Pop double, convert to int, push int</P>
<P>20 imul // Pop two ints, multiply, push int result</P>
<P> // Pop int, store into class variable</P>
<P> // width</P>
<P>21 putstatic #7 <Field int width</FONT></P>
<P>24 return // Return void from <clinit</FONT> method</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>This <FONT FACE="Courier New"><clinit</FONT>()</FONT> method first executes the code for <FONT FACE="Courier New">Example1c</FONT>韘 only class variable initializer, which initializes <FONT FACE="Courier New">height</FONT>, then executes the code for the static initializer, which initializes <FONT FACE="Courier New">width</FONT>. The initialization is done in this order because the class variable initializer appears textually before the static initializer in the source code of the <FONT FACE="Courier New">Example1c</FONT> class.</P>
<P>Not all classes will necessarily have a <FONT FACE="Courier New"><clinit</FONT>()</FONT> method in their class file. If a class declares no class variables, it won韙 have a <FONT FACE="Courier New"><clinit</FONT>()</FONT> method. If a class declares class variables, but doesn韙 explicitly initialize them with class variable initializers or static initializers, it won韙 have a <FONT FACE="Courier New"><clinit</FONT>()</FONT> method. If a class contains only class variable initializers for static final variables, and those class variable initializers use compile-time constant expressions, that class won韙 have a <FONT FACE="Courier New"><clinit</FONT>()</FONT> method. Only those classes that actually require Java code to be executed to initialize class variables to proper initial values will have a class initialization method.</P>
<P>Here韘 an example of a class that won韙 be awarded a <FONT FACE="Courier New"><clinit</FONT>()</FONT> method by the Java compiler:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// On CD-ROM in file classlife/ex1/Example1d.java
<P>class Example1d {</P>
<P> </P>
<P> static final int angle = 35;</P>
<P> static final int length = angle * 2;</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>Class <FONT FACE="Courier New">Example1d</FONT> declares two constants, <FONT FACE="Courier New">angle</FONT> and <FONT FACE="Courier New">length</FONT>, and initializes them with expressions that are compile-time constants. The compiler knows that <FONT FACE="Courier New">angle</FONT> represents the value 35 and <FONT FACE="Courier New">length</FONT> represents the value 70. When the <FONT FACE="Courier New">Example1d</FONT> class is loaded by a Java Virtual Machine, <FONT FACE="Courier New">angle</FONT> and <FONT FACE="Courier New">length</FONT> are not stored as class variables in the method area. As a result, no <FONT FACE="Courier New"><clinit</FONT>()</FONT> method is needed to initialize them. The <FONT FACE="Courier New">angle</FONT> and <FONT FACE="Courier New">length</FONT> fields are not class variables, they are constants, which are treated specially by the Java compiler.</P>
<P>Instead of treating <FONT FACE="Courier New">Example1d</FONT>韘 <FONT FACE="Courier New">angle</FONT> and <FONT FACE="Courier New">length</FONT> fields as class variables, the Java compiler places the constant <FONT FACE="Courier New">int</FONT> values they represent into the constant pool or bytecode streams of any class that uses them. For example, if a class uses <FONT FACE="Courier New">Example1d</FONT>韘 <FONT FACE="Courier New">angle</FONT> field, that class will not have in its constant pool a symbolic reference to the <FONT FACE="Courier New">angle</FONT> field of class <FONT FACE="Courier New">Example1d</FONT>. Instead, the class will have operands embedded in its bytecode streams that have the value 35. If the constant value of <FONT FACE="Courier New">angle</FONT> were outside the range of a <FONT FACE="Courier New">short</FONT> (-32,768 to 32,767), say 35,000, the class would have a <FONT FACE="Courier New">CONSTANT_Integer_info</FONT> entry in its constant pool with the value of 35,000.</P>
<P>Here韘 a class that uses both a constant and a class variable from other classes:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// On CD-ROM in file classlife/ex1/Example1e.java
<P>class Example1e {</P>
<P> </P>
<P> // The class variable initializer for symbolicRef uses a symbolic</P>
<P> // reference to the size class variable of class Example1a</P>
<P> static int symbolicRef = Example1a.size;</P>
<P> </P>
<P> // The class variable initializer for localConst doesn't use a</P>
<P> // symbolic reference to the length field of class Example1d.</P>
<P> // Instead, it just uses a copy of the constant value 70.</P>
<P> static int localConst = Example1d.length * (int) (Math.random()</P>
<P> * 3.0);</P>
<P>}</P>
</FONT><FONT SIZE="2"><P> </P></FONT><FONT FACE="Courier New">end</FONT></P></PRE>
<P>The Java compiler generates the following <FONT FACE="Courier New"><clinit</FONT>()</FONT> method for class Example1e:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// The code for symbolicRef's class variable initializer begins here:
<P> // Push int value from Example1a.size.</P>
<P> // This getstatic instruction refers to a</P>
<P> // symbolic reference to Example1a.size.</P>
<P> 0 getstatic #9 <Field int size</FONT></P>
<P> // Pop int, store into class variable</P>
<P> // symbolicRef</P>
<P> 3 putstatic #10 <Field int symbolicRef</FONT></P>
<P> </P>
<P>// The code for localConst's class variable intializer begins here:</P>
<P> // Expand byte operand to int, push int</P>
<P> // result. This is the local copy of</P>
<P> 6 bipush 70 // Example1d's length constant, 70.</P>
<P> // Invoke Math.random(), which will push</P>
<P> // a double return value</P>
<P> 8 invokestatic #8 <Method double random()</FONT></P>
<P>11 ldc2_w #11 <Double 3.0</FONT> // Push double constant 3.0</P>
<P>14 dmul // Pop two doubles, multiply, push result</P>
<P>15 d2i // Pop double, convert to int, push int</P>
<P>16 imul // Pop two ints, multiply, push int result</P>
<P> // Pop int, store into class variable</P>
<P> // localConst</P>
<P>17 putstatic #7 <Field int localConst</FONT></P>
<P>20 return // Return void from <clinit</FONT> method</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -