辐射4避难所dlc下载:Execution.doc
来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 15:24:56
Second Edition
CHAPTER12
Execution
This chapter specifies activities that occur during execution of aprogram. It is organized around the life cycle of a Java virtual machineand of the classes, interfaces, and objects that form a program.
A Java virtual machine starts up by loading a specified class and then invoking the method main
in this specified class. Section §12.1 outlines the loading, linking, and initialization steps involved in executing main
, as an introduction to the concepts in this chapter. Further sections specify the details of loading (§12.2), linking (§12.3), and initialization (§12.4).
The chapter continues with a specification of the procedures for creation of new class instances (§12.5); and finalization of class instances (§12.6). It concludes by describing the unloading of classes (§12.7) and the procedure followed when a program exits (§12.8).
12.1 Virtual Machine Start-Up
A Java virtual machine starts execution by invoking the methodmain
of some specified class, passing it a single argument, which is anarray of strings. In the examples in this specification, this firstclass is typically called Test
.The precise semantics of virtual machine start-up are given in chapter 5 of The Java Virtual Machine Specification, Second Edition. Here we present an overview of the process from the viewpoint of the Java programming language.
The manner in which the initial class is specified to the Java virtualmachine is beyond the scope of this specification, but it is typical, inhost environments that use command lines, for the fully-qualified nameof the class to be specified as a command-line argument and forfollowing command-line arguments to be used as strings to be provided asthe argument to the method main
. For example, in a UNIX implementation, the command line:
will typically start a Java virtual machine by invoking methodjava Test reboot Bob Dot Enzo
main
of class Test
(a class in an unnamed package), passing it an array containing the four strings "reboot"
, "Bob"
, "Dot"
, and "Enzo"
.We now outline the steps the virtual machine may take to execute Test
, as an example of the loading, linking, and initialization processes that are described further in later sections.
12.1.1 Load the Class Test
The initial attempt to execute the methodmain
of class Test
discovers that the class Test
is not loaded-that is, that the virtual machine does not currentlycontain a binary representation for this class. The virtual machine thenuses a class loader to attempt to find such a binary representation. Ifthis process fails, then an error is thrown. This loading process isdescribed further in §12.2.12.1.2 Link Test: Verify, Prepare, (Optionally) Resolve
AfterTest
is loaded, it must be initialized before main
can be invoked. And Test
,like all (class or interface) types, must be linked before it isinitialized. Linking involves verification, preparation and (optionally)resolution. Linking is described further in §12.3.Verification checks that the loaded representation of Test
is well-formed, with a proper symbol table. Verification also checks that the code that implements Test
obeys the semantic requirements of the Java programming language andthe Java virtual machine. If a problem is detected during verification,then an error is thrown. Verification is described further in §12.3.1.
Preparation involves allocation of static storage and any datastructures that are used internally by the virtual machine, such asmethod tables. Preparation is described further in §12.3.2.
Resolution is the process of checking symbolic references from Test
to other classes and interfaces, by loading the other classes andinterfaces that are mentioned and checking that the references arecorrect.
The resolution step is optional at the time of initial linkage. Animplementation may resolve symbolic references from a class or interfacethat is being linked very early, even to the point of resolving allsymbolic references from the classes and interfaces that are furtherreferenced, recursively. (This resolution may result in errors fromthese further loading and linking steps.) This implementation choicerepresents one extreme and is similar to the kind of "static" linkagethat has been done for many years in simple implementations of the Clanguage. (In these implementations, a compiled program is typicallyrepresented as an "a.out
" file that contains afully-linked version of the program, including completely resolved linksto library routines used by the program. Copies of these libraryroutines are included in the "a.out
" file.)
An implementation may instead choose to resolve a symbolic referenceonly when it is actively used; consistent use of this strategy for allsymbolic references would represent the "laziest" form of resolution.
In this case, if Test
had several symbolic references toanother class, then the references might be resolved one at a time, asthey are used, or perhaps not at all, if these references were neverused during execution of the program.
The only requirement on when resolution is performed is that any errorsdetected during resolution must be thrown at a point in the programwhere some action is taken by the program that might, directly orindirectly, require linkage to the class or interface involved in theerror. Using the "static" example implementation choice described above,loading and linkage errors could occur before the program is executedif they involved a class or interface mentioned in the class Test
or any of the further, recursively referenced, classes and interfaces.In a system that implemented the "laziest" resolution, these errorswould be thrown only when an incorrect symbolic reference is activelyused.
The resolution process is described further in §12.3.3.
12.1.3 Initialize Test: Execute Initializers
In our continuing example, the virtual machine is still trying to execute the methodmain
of class Test
. This is permitted only if the class has been initialized (§12.4.1).Initialization consists of execution of any class variable initializers and static initializers of the class Test
, in textual order. But before Test
can be initialized, its direct superclass must be initialized, as wellas the direct superclass of its direct superclass, and so on,recursively. In the simplest case, Test
has Object
as its implicit direct superclass; if class Object
has not yet been initialized, then it must be initialized before Test
is initialized. Class Object
has no superclass, so the recursion terminates here.
If class Test
has another class Super
as its superclass, then Super
must be initialized before Test
. This requires loading, verifying, and preparing Super
if this has not already been done and, depending on the implementation,may also involve resolving the symbolic references from Super
and so on, recursively.
Initialization may thus cause loading, linking, and initialization errors, including such errors involving other types.
The initialization process is described further in §12.4.
12.1.4 Invoke Test.main
Finally, after completion of the initialization for classTest
(during which other consequential loading, linking, and initializing may have occurred), the method main
of Test
is invoked.The method main
must be declared public
, static
, and void
. It must accept a single argument that is an array of strings.
12.2 Loading of Classes and Interfaces
Loading refers to the process of finding the binary form of aclass or interface type with a particular name, perhaps by computing iton the fly, but more typically by retrieving a binary representationpreviously computed from source code by a compiler, and constructing,from that binary form, aClass
object to represent the class or interface.The precise semantics of loading are given in chapter 5 of The Java Virtual Machine Specification, Second Edition. Here we present an overview of the process from the viewpoint of the Java programming language.
The binary format of a class or interface is normally the class
file format described in The Java Virtual Machine Specification cited above, but other formats are possible, provided they meet the requirements specified in §13.1. The method defineClass
of class ClassLoader
may be used to construct Class
objects from binary representations in the class
file format.
Well-behaved class loaders maintain these properties:
- Given the same name, a good class loader should always return the same class object.
- If a class loader L1 delegates loading of a class C to another loader L2, then for any type T that occurs as the direct superclass or a direct superinterface of C, or as the type of a field in C, or as the type of a formal parameter of a method or constructor in C, or as a return type of a method in C, L1 and L2 should return the same class object.
For further discussion of these issues, see The Java Virtual Machine Specification, Second Edition and the paper Dynamic Class Loading in the Java Virtual Machine, by Sheng Liang and Gilad Bracha, in Proceedings of OOPSLA '98, published as ACM SIGPLAN Notices,Volume 33, Number 10, October 1998, pages 36-44. A basic principle ofthe design of the Java programming language is that the type systemcannot be subverted by code written in the language, not even byimplementations of such otherwise sensitive system classes as ClassLoader
and SecurityManager
.
12.2.1 The Loading Process
The loading process is implemented by the classClassLoader
and its subclasses. Different subclasses of ClassLoader
may implement different loading policies. In particular, a class loadermay cache binary representations of classes and interfaces, prefetchthem based on expected usage, or load a group of related classestogether. These activities may not be completely transparent to arunning application if, for example, a newly compiled version of a classis not found because an older version is cached by a class loader. Itis the responsibility of a class loader, however, to reflect loadingerrors only at points in the program they could have arisen withoutprefetching or group loading.If an error occurs during class loading, then an instance of one of the following subclasses of class LinkageError
will be thrown at any point in the program that (directly or indirectly) uses the type:
ClassCircularityError
: A class or interface could not be loaded because it would be its own superclass or superinterface (§13.4.4).ClassFormatError
: The binary data that purports to specify a requested compiled class or interface is malformed.NoClassDefFoundError
: No definition for a requested class or interface could be found by the relevant class loader.
OutOfMemoryError
.12.3 Linking of Classes and Interfaces
Linking is the process of taking a binary form of a class orinterface type and combining it into the runtime state of the Javavirtual machine, so that it can be executed. A class or interface typeis always loaded before it is linked.Three different activities are involved in linking: verification,preparation, and resolution of symbolic references.The precise semanticsof linking are given in chapter 5 of The Java Virtual Machine Specification, Second Edition. Here we present an overview of the process from the viewpoint of the Java programming language.
This specification allows an implementation flexibility as to whenlinking activities (and, because of recursion, loading) take place,provided that the semantics of the language are respected, that a classor interface is completely verified and prepared before it isinitialized, and that errors detected during linkage are thrown at apoint in the program where some action is taken by the program thatmight require linkage to the class or interface involved in the error.
For example, an implementation may choose to resolve each symbolicreference in a class or interface individually, only when it is used(lazy or late resolution), or to resolve them all at once while theclass is being verified (static resolution). This means that theresolution process may continue, in some implementations, after a classor interface has been initialized.
Because linking involves the allocation of new data structures, it may fail with an OutOfMemoryError
.
12.3.1 Verification of the Binary Representation
Verification ensures that the binary representation of a classor interface is structurally correct. For example, it checks that everyinstruction has a valid operation code; that every branch instructionbranches to the start of some other instruction, rather than into themiddle of an instruction; that every method is provided with astructurally correct signature; and that every instruction obeys thetype discipline of the Java virtual machine language.For the specification of the verification process, see the separate volume of this series, The Java Virtual Machine Specification, Second Edition.
If an error occurs during verification, then an instance of the following subclass of class LinkageError
will be thrown at the point in the program that caused the class to be verified:
VerifyError
: The binary definition for a class or interface failed to pass a set of required checks to verify that it obeys the semantics of the Java virtual machine language and that it cannot violate the integrity of the Java virtual machine. (See §13.4.2, §13.4.4, §13.4.8, and §13.4.15 for some examples.)
12.3.2 Preparation of a Class or Interface Type
Preparation involves creating thestatic
fields (class variables and constants) for a class or interface and initializing such fields to the default values (§4.5.5). This does not require the execution of any source code; explicit initializers for static
fields are executed as part of initialization (§12.4), not preparation.Implementations of the Java virtual machine may precompute additionaldata structures at preparation time in order to make later operations ona class or interface more efficient. One particularly useful datastructure is a "method table" or other data structure that allows anymethod to be invoked on instances of a class without requiring a searchof superclasses at invocation time.
12.3.3 Resolution of Symbolic References
The binary representation of a class or interface references otherclasses and interfaces and their fields, methods, and constructorssymbolically, using the binary names (§13.1) of the other classes and interfaces (§13.1).For fields and methods, these symbolic references include the name ofthe class or interface type that declares the field or method as well asthe name of the field or method itself, together with appropriate typeinformation.Before a symbolic reference can be used it must undergo resolution,wherein a symbolic reference is checked to be correct and, typically,replaced with a direct reference that can be more efficiently processedif the reference is used repeatedly.
If an error occurs during resolution, then an error will be thrown. Mosttypically, this will be an instance of one of the following subclassesof the class IncompatibleClassChangeError
, but it may also be an instance of some other subclass of IncompatibleClassChangeError
or even an instance of the class IncompatibleClassChangeError
itself. This error may be thrown at any point in the program that uses asymbolic reference to the type, directly or indirectly:
IllegalAccessError
: A symbolic reference has been encountered that specifies a use or assignment of a field, or invocation of a method, or creation of an instance of a class, to which the code containing the reference does not have access because the field or method was declaredprivate
,protected
, or default access (notpublic
), or because the class was not declaredpublic
.
public
is changed to be private
after another class that refers to the field has been compiled (§13.4.6).InstantiationError
: A symbolic reference has been encountered that is used in a class instance creation expression, but an instance cannot be created because the reference turns out to refer to an interface or to anabstract
class.
abstract
is changed to be abstract
after another class that refers to the class in question has been compiled (§13.4.1).NoSuchFieldError
: A symbolic reference has been encountered that refers to a specific field of a specific class or interface, but the class or interface does not contain a field of that name.
NoSuchMethodError
: A symbolic reference has been encountered that refers to a specific method of a specific class or interface, but the class or interface does not contain a method of that signature.
Additionally, an UnsatisfiedLinkError
(a subclass of LinkageError
) may be thrown if a class declares a native
method for which no implementation can be found. The error will occurif the method is used, or earlier, depending on what kind of resolutionstrategy is being used by the virtual machine (§12.3).
12.4 Initialization of Classes and Interfaces
Initialization of a class consists of executing its static initializers and the initializers forstatic
fields (class variables) declared in the class. Initialization of aninterface consists of executing the initializers for fields (constants)declared there.Before a class is initialized, its superclass must be initialized, butinterfaces implemented by the class are not initialized. Similarly, thesuperinterfaces of an interface are not initialized before the interfaceis initialized.
12.4.1 When Initialization Occurs
Initialization of a class consists of executing its static initializers and the initializers for static fields declared in the class. Initialization of an interface consists of executing the initializers for fields declared in the interface.Before a class is initialized, its direct superclass must beinitialized, but interfaces implemented by the class need not beinitialized. Similarly, the superinterfaces of an interface need not beinitialized before the interface is initialized.
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
- T is a class and an instance of T is created.
- T is a class and a static method declared by T is invoked.
- A static field declared by T is assigned.
- A static field declared by T is used and the reference to the field is not a compile-time constant (§15.28). References to compile-time constants must be resolved at compile time to a copy of the compile-time constant value, so uses of such a field never cause initialization.
Class
and in package java.lang.reflect
also causes class or interface initialization. A class or interface will not be initialized under any other circumstance.The intent here is that a class or interface type has a set ofinitializers that put it in a consistent state, and that this state isthe first state that is observed by other classes. The staticinitializers and class variable initializers are executed in textualorder, and may not refer to class variables declared in the class whosedeclarations appear textually after the use, even though these classvariables are in scope (§8.3.2.3). This restriction is designed to detect, at compile time, most circular or otherwise malformed initializations.
As shown in an example in §8.3.2.3,the fact that initialization code is unrestricted allows examples to beconstructed where the value of a class variable can be observed when itstill has its initial default value, before its initializing expressionis evaluated, but such examples are rare in practice. (Such examplescan also be constructed for instance variable initialization; see theexample at the end of §12.5).The full power of the language is available in these initializers;programmers must exercise some care. This power places an extra burdenon code generators, but this burden would arise in any case because thelanguage is concurrent (§12.4.3).
Before a class is initialized, its superclasses are initialized, if they have not previously been initialized.
Thus, the test program:
prints:class Super {static { System.out.print("Super "); }}class One {static { System.out.print("One "); }}class Two extends Super {static { System.out.print("Two "); }}class Test {public static void main(String[] args) {One o = null;Two t = new Two();System.out.println((Object)o == (Object)t);}}
The classSuper Two false
One
is never initialized, because it not used actively and therefore is never linked to. The class Two
is initialized only after its superclass Super
has been initialized.A reference to a class field causes initialization of only the class orinterface that actually declares it, even though it might be referred tothrough the name of a subclass, a subinterface, or a class thatimplements an interface.
The test program:
prints only:class Super { static int taxi = 1729; }class Sub extends Super {static { System.out.print("Sub "); }}class Test {public static void main(String[] args) {System.out.println(Sub.taxi);}}
because the class1729
Sub
is never initialized; the reference to Sub.taxi
is a reference to a field actually declared in class Super
and does not trigger initialization of the class Sub
.Initialization of an interface does not, of itself, cause initialization of any of its superinterfaces.
Thus, the test program:
produces the output:interface I {int i = 1, ii = Test.out("ii", 2);}interface J extends I {int j = Test.out("j", 3), jj = Test.out("jj", 4);}interface K extends J {int k = Test.out("k", 5);}class Test {public static void main(String[] args) {System.out.println(J.i);System.out.println(K.j);}static int out(String s, int i) {System.out.println(s + "=" + i);return i;}}
The reference to1j=3jj=43
J.i
is to a field that is a compile-time constant; therefore, it does not cause I
to be initialized. The reference to K.j
is a reference to a field actually declared in interface J
that is not a compile-time constant; this causes initialization of the fields of interface J
, but not those of its superinterface I
, nor those of interface K
. Despite the fact that the name K
is used to refer to field j
of interface J
, interface K
is not initialized.12.4.2 Detailed Initialization Procedure
Because the Java programming language is multithreaded, initializationof a class or interface requires careful synchronization, since someother thread may be trying to initialize the same class or interface atthe same time. There is also the possibility that initialization of aclass or interface may be requested recursively as part of theinitialization of that class or interface; for example, a variableinitializer in class A might invoke a method of an unrelated class B, which might in turn invoke a method of class A.The implementation of the Java virtual machine is responsible fortaking care of synchronization and recursive initialization by using thefollowing procedure. It assumes that theClass
object has already been verified and prepared, and that the Class
object contains state that indicates one of four situations:- This
Class
object is verified and prepared but not initialized. - This
Class
object is being initialized by some particular thread T. - This
Class
object is fully initialized and ready for use. - This
Class
object is in an erroneous state, perhaps because the verification or preparation step failed, or because initialization was attempted and failed.
- Synchronize (§14.18) on the
Class
object that represents the class or interface to be initialized. This involves waiting until the current thread can obtain the lock for that object (§17.13). - If initialization is in progress for the class or interface by some other thread, then
wait
on thisClass
object (which temporarily releases the lock). When the current thread awakens from thewait
, repeat this step. - If initialization is in progress for the class or interface by the current thread, then this must be a recursive request for initialization. Release the lock on the
Class
object and complete normally. - If the class or interface has already been initialized, then no further action is required. Release the lock on the
Class
object and complete normally. - If the
Class
object is in an erroneous state, then initialization is not possible. Release the lock on theClass
object and throw aNoClassDefFoundError
. - Otherwise, record the fact that initialization of the
Class
object is now in progress by the current thread and release the lock on theClass
object. - Next, if the
Class
object represents a class rather than an interface, and the superclass of this class has not yet been initialized, then recursively perform this entire procedure for the superclass. If necessary, verify and prepare the superclass first. If the initialization of the superclass completes abruptly because of a thrown exception, then lock thisClass
object, label it erroneous, notify all waiting threads, release the lock, and complete abruptly, throwing the same exception that resulted from initializing the superclass. - Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block, except that
final
class variables and fields of interfaces whose values are compile-time constants are initialized first (§8.3.2.1, §9.3.1, §13.4.8). - If the execution of the initializers completes normally, then lock this
Class
object, label it fully initialized, notify all waiting threads, release the lock, and complete this procedure normally. - Otherwise, the initializers must have completed abruptly by throwing some exception E. If the class of E is not
Error
or one of its subclasses, then create a new instance of the classExceptionInInitializerError
, with E as the argument, and use this object in place of E in the following step. But if a new instance ofExceptionInInitializerError
cannot be created because anOutOfMemoryError
occurs, then instead use anOutOfMemoryError
object in place of E in the following step. - Lock the
Class
object, label it erroneous, notify all waiting threads, release the lock, and complete this procedure abruptly with reason E or its replacement as determined in the previous step. (Due to a flaw in some early implementations, a exception during class initialization was ignored, rather than causing anExceptionInInitializerError
as described here.)
12.4.3 Initialization: Implications for Code Generation
Code generators need to preserve the points of possible initializationof a class or interface, inserting an invocation of the initializationprocedure just described. If this initialization procedure completesnormally and theClass
object is fully initialized andready for use, then the invocation of the initialization procedure is nolonger necessary and it may be eliminated from the code-for example, bypatching it out or otherwise regenerating the code.Compile-time analysis may, in some cases, be able to eliminate many ofthe checks that a type has been initialized from the generated code, ifan initialization order for a group of related types can be determined.Such analysis must, however, fully account for concurrency and for thefact that initialization code is unrestricted.
12.5 Creation of New Class Instances
A new class instance is explicitly created when evaluation of a class instance creation expression (§15.9) causes a class to be instantiated.A new class instance may be implicitly created in the following situations:
- Loading of a class or interface that contains a
String
literal (§3.10.5) may create a newString
object to represent that literal. (This might not occur if the sameString
has previously been interned (§3.10.5).) - Execution of a string concatenation operator (§15.18.1) that is not part of a constant expression sometimes creates a new
String
object to represent the result. String concatenation operators may also create temporary wrapper objects for a value of a primitive type.
Whenever a new class instance is created, memory space is allocated forit with room for all the instance variables declared in the class typeand all the instance variables declared in each superclass of the classtype, including all the instance variables that may be hidden (§8.3).If there is not sufficient space available to allocate memory for theobject, then creation of the class instance completes abruptly with an OutOfMemoryError
.Otherwise, all the instance variables in the new object, includingthose declared in superclasses, are initialized to their default values (§4.5.5).
Just before a reference to the newly created object is returned as theresult, the indicated constructor is processed to initialize the newobject using the following procedure:
- Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
- If this constructor begins with an explicit constructor invocation of another constructor in the same class (using
this
), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5. - This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using
this
). If this constructor is for a class other thanObject
, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (usingsuper
). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4. - Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5. (In some early implementations, the compiler incorrectly omitted the code to initialize a field if the field initializer expression was a constant expression whose value was equal to the default initialization value for its type.)
- Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally. In the example:
a new instance ofclass Point {int x, y;Point() { x = 1; y = 1; }}class ColoredPoint extends Point {int color = 0xFF00FF;}class Test {public static void main(String[] args) {ColoredPoint cp = new ColoredPoint();System.out.println(cp.color);}}
ColoredPoint
is created. First, space is allocated for the new ColoredPoint
, to hold the fields x
, y
, and color
. All these fields are then initialized to their default values (in this case, 0
for each field). Next, the ColoredPoint
constructor with no arguments is first invoked. Since ColoredPoint
declares no constructors, a default constructor of the form:is provided for it automatically by the Java compiler.ColoredPoint() { super(); }
This constructor then invokes the Point
constructor with no arguments. The Point
constructor does not begin with an invocation of a constructor, so thecompiler provides an implicit invocation of its superclass constructorof no arguments, as though it had been written:
Therefore, the constructor forPoint() { super(); x = 1; y = 1; }
Object
which takes no arguments is invoked.The class Object
has no superclass, so the recursion terminates here. Next, any instance initializers, instance variable initializers of Object
are invoked. Next, the body of the constructor of Object
that takes no arguments is executed. No such constructor is declared in Object
, so the compiler supplies a default one, which in this special case is:
This constructor executes without effect and returns.Object() { }
Next, all initializers for the instance variables of class Point
are executed. As it happens, the declarations of x
and y
do not provide any initialization expressions, so no action is required for this step of the example. Then the body of the Point
constructor is executed, setting x
to 1
and y
to 1
.
Next, the initializers for the instance variables of class ColoredPoint
are executed. This step assigns the value 0xFF00FF
to color
. Finally, the rest of the body of the ColoredPoint
constructor is executed (the part after the invocation of super
); there happen to be no statements in the rest of the body, so no further action is required and initialization is complete.
Unlike C++, the Java programming language does not specify altered rulesfor method dispatch during the creation of a new class instance. Ifmethods are invoked that are overridden in subclasses in the objectbeing initialized, then these overriding methods are used, even beforethe new object is completely initialized. Thus, compiling and runningthe example:
produces the output:class Super {Super() { printThree(); }void printThree() { System.out.println("three"); }}class Test extends Super {int three = (int)Math.PI;// That is, 3public static void main(String[] args) {Test t = new Test();t.printThree();}void printThree() { System.out.println(three); }}
This shows that the invocation of0
3
printThree
in the constructor for class Super
does not invoke the definition of printThree
in class Super
, but rather invokes the overriding definition of printThree
in class Test
. This method therefore runs before the field initializers of Test
have been executed, which is why the first value output is 0
, the default value to which the field three
of Test
is initialized. The later invocation of printThree
in method main
invokes the same definition of printThree
, but by that point the initializer for instance variable three
has been executed, and so the value 3
is printed.See §8.8 for more details on constructor declarations.
12.6 Finalization of Class Instances
The classObject
has a protected
method called finalize
; this method can be overridden by other classes. The particular definition of finalize
that can be invoked for an object is called the finalizerof that object. Before the storage for an object is reclaimed by thegarbage collector, the Java virtual machine will invoke the finalizer of that object.Finalizers provide a chance to free up resources that cannot be freedautomatically by an automatic storage manager. In such situations,simply reclaiming the memory used by an object would not guarantee thatthe resources it held would be reclaimed.
The Java programming language does not specify how soon a finalizer willbe invoked, except to say that it will happen before the storage forthe object is reused. Also, the language does not specify which threadwill invoke the finalizer for any given object. It is guaranteed,however, that the thread that invokes the finalizer will not be holdingany user-visible synchronization locks when the finalizer is invoked. Ifan uncaught exception is thrown during the finalization, the exceptionis ignored and finalization of that object terminates.
The finalize
method declared in class Object
takes no action.
The fact that class Object
declares a finalize
method means that the finalize
method for any class can always invoke the finalize
method for its superclass, which is usually good practice. (Unlikeconstructors, finalizers do not automatically invoke the finalizer forthe superclass; such an invocation must be coded explicitly.)
For efficiency, an implementation may keep track of classes that do not override the finalize
method of class Object
, or override it in a trivial way, such as:
We encourage implementations to treat such objects as having a finalizerthat is not overridden, and to finalize them more efficiently, asdescribed in §12.6.1.protected void finalize() throws Throwable {super.finalize();}
A finalizer may be invoked explicitly, just like any other method.
The package java.lang.ref
describes weak references, whichinteract with garbage collection and finalization. As with any API thathas special interactions with the language, implementors must becognizant of any requirements imposed by the java.lang.ref
API. This specification does not discuss weak references in any way. Readers are referred to the API documentation for details.
12.6.1 Implementing Finalization
Every object can be characterized by two attributes: it may be reachable, finalizer-reachable, or unreachable, and it may also be unfinalized, finalizable, or finalized.A reachable object is any object that can be accessed in anypotential continuing computation from any live thread. Optimizingtransformations of a program can be designed that reduce the number ofobjects that are reachable to be less than those which would naively beconsidered reachable. For example, a compiler or code generator maychoose to set a variable or parameter that will no longer be used to null
to cause the storage for such an object to be potentially reclaimable sooner. A finalizer-reachable object can be reached from some finalizable object through some chain of references, but not from any live thread. An unreachable object cannot be reached by either means.
An unfinalized object has never had its finalizer automatically invoked; a finalized object has had its finalizer automatically invoked. A finalizableobject has never had its finalizer automatically invoked, but the Javavirtual machine may eventually automatically invoke its finalizer.
The life cycle of an object obeys the following transition diagram, where we abbreviate "finalizer-reachable" as "f-reachable":
When an object is first created (A), it is reachable and unfinalized.
As references to an object are discarded during program execution, anobject that was reachable may become finalizer-reachable (B, C, D) orunreachable (E, F). (Note that a finalizer-reachable object neverbecomes unreachable directly; it becomes reachable when the finalizerfrom which it can be reached is invoked, as explained below.)
If the Java virtual machine detects that an unfinalized object hasbecome finalizer-reachable or unreachable, it may label the objectfinalizable (G, H); moreover, if the object was unreachable, it becomesfinalizer-reachable (H).
If the Java virtual machine detects that a finalized object has becomeunreachable, it may reclaim the storage occupied by the object becausethe object will never again become reachable (I).
At any time, a Java virtual machine may take any finalizable object, label it finalized, and then invoke its finalize
method in some thread. This causes the object to become finalized andreachable (J, K), and it also may cause other objects that werefinalizer-reachable to become reachable again (L, M, N).
A finalizable object cannot also be unreachable; it can be reachedbecause its finalizer may eventually be invoked, whereupon the threadrunning the finalizer will have access to the object, as this
(§15.8.3). Thus, there are actually only eight possible states for an object.
After an object has been finalized, no further action is taken until theautomatic storage management determines that it is unreachable. Becauseof the way that an object progresses from the unfinalized state through the finalizable state to the finalized state, the finalize
method is never automatically invoked more than once by a Java virtualmachine for each object, even if the object is again made reachableafter it has been finalized.
Explicit invocation of a finalizer ignores the current state of theobject and does not change the state of the object from unfinalized orfinalizable to finalized.
If a class does not override method finalize
of class Object
(or overrides it in only a trivial way, as described above), then ifinstances of such a class become unreachable, they may be discardedimmediately rather than made to await a second determination that theyhave become unreachable. This strategy is indicated by the dashed arrow(O) in the transition diagram.
Therefore, we recommend that the design of finalize
methods be kept simple and that they be programmed defensively, so that they will work in all cases.
12.6.2 Finalizer Invocations are Not Ordered
The Java programming language imposes no ordering on finalize methodcalls. Finalizers may be called in any order, or even concurrently.As an example, if a circularly linked group of unfinalized objectsbecomes unreachable (or finalizer-reachable), then all the objects maybecome finalizable together. Eventually, the finalizers for theseobjects may be invoked, in any order, or even concurrently usingmultiple threads. If the automatic storage manager later finds that theobjects are unreachable, then their storage can be reclaimed.
It is straightforward to implement a class that will cause a set offinalizer-like methods to be invoked in a specified order for a set ofobjects when all the objects become unreachable. Defining such a classis left as an exercise for the reader.
12.7 Unloading of Classes and Interfaces
An implementation of the Java programming language may unloadclasses. A class or interface may be unloaded if and only if itsdefining class loader may be reclaimed by the garbage collector asdiscussed in §12.6. Classes and interfaces loaded by the bootstrap loader may not be unloaded.Here is the rationale for the rule given in the previous paragraph:
Class unloading is an optimization that helps reduce memory use.Obviously, the semantics of a program should not depend on whether andhow a system chooses to implement an optimization such as classunloading. To do otherwise would compromise the portability of programs.Consequently, whether a class or interface has been unloaded or notshould be transparent to a program.
However, if a class or interface C was unloaded while its defining loader was potentially reachable, then Cmight be reloaded. One could never ensure that this would not happen.Even if the class was not referenced by any other currently loadedclass, it might be referenced by some class or interface, D, that had not yet been loaded. When D is loaded by C's defining loader, its execution might cause reloading of C.
Reloading may not be transparent if, for example, the class has:
- Static variables (whose state would be lost).
- Static initializers (which may have side effects).
- Native methods (which may retain static state).
Class
object is dependenton its identity. Therefore it is, in general, impossible to reload aclass or interface in a completely transparent manner.Since we can never guarantee that unloading a class or interface whoseloader is potentially reachable will not cause reloading, and reloadingis never transparent, but unloading must be transparent, it follows thatone must not unload a class or interface while its loader ispotentially reachable. A similar line of reasoning can be used to deducethat classes and interfaces loaded by the bootstrap loader can never beunloaded.
One must also argue why it is safe to unload a class C if itsdefining class loader can be reclaimed. If the defining loader can bereclaimed, then there can never be any live references to it (thisincludes references that are not live, but might be resurrected byfinalizers). This, in turn, can only be true if there are can never beany live references to any of the classes defined by that loader,including C, either from their instances or from code.
Class unloading is an optimization that is only significant forapplications that load large numbers of classes and that stop using mostof those classes after some time. A prime example of such anapplication is a web browser, but there are others. A characteristic ofsuch applications is that they manage classes through explicit use ofclass loaders. As a result, the policy outlined above works well forthem.
Strictly speaking, it is not essential that the issue of class unloadingbe discussed by this specification, as class unloading is merely anoptimization. However, the issue is very subtle, and so it is mentionedhere by way of clarification.
12.8 Program Exit
A program terminates all its activity and exits when one of two things happens:- All the threads that are not daemon threads terminate.
- Some thread invokes the
exit
method of classRuntime
or classSystem
and the exit operation is not forbidden by the security manager.
Contents | Prev | Next | Index Java Language Specification
Second Edition Copyright ? 2000 Sun Microsystems, Inc.All rights reserved
Please send any comments or corrections via our feedback form