An object is only eligible for garbage collection if all remaining references to the object are from other objects that are also eligible for garbage collection. Therefore, if an object obj2 is eligible for garbage collection and object obj1 contains a reference to it, then object obj1 must also be eligible for garbage collection. Java does not have a keyword delete. An object will not necessarily be garbage collected immediately after it becomes unreachable. However, the object will be eligible for garbage collection. Circular references do not prevent objects from being garbage collected, only reachable references do. An object is not eligible for garbage collection as long as the object can be accessed by any live thread. An object that has been eligible for garbage collection can be made non-eligible. This occurs if the finalize() method of the object creates a reachable reference to the object.
Before (1), the String object initially referenced by arg1 is denoted by both msg and arg1. After (1), the String object is only denoted by msg. At (2), reference msg is assigned a new reference value. This reference value denotes a new String object created by concatenating several other String objects. After (2), there are no references to the String object initially referenced by arg1. The String object is now eligible for garbage collection.
The Object class defines a protected finalize() method. All classes inherit from Object, thus, all objects have a finalize() method. Classes can override the finalize() method and, as with all overriding, the new method must not reduce the accessibility. The finalize() method of an eligible object is called by the garbage collector to allow the object to do any cleaning up, before the object is destroyed. When the garbage collector calls the finalize() method, it will ignore any exceptions thrown by the finalize() method. In all other cases, normal exception handling occurs when an exception is thrown during the execution of the finalize() method, that is, exceptions are not simply ignored. Calling the finalize() method does not in itself destroy the object. Chaining of the finalize() methods is not enforced by the compiler, and it is not mandatory to call the overridden finalize() method.
The finalize() method is like any other method, it can be called explicitly if it is accessible. However, the intended purpose of the method is to be called by the garbage collector in order to clean up before an object is destroyed. Overloading the finalize() method name is allowed, but only the method with the original signature will be called by the garbage collector. The finalize() method in Object is protected. This means that overriding methods must be declared either protected or public. The finalize() method in Object can throw any Throwable object. Overriding methods can limit the range of throwables to unchecked exceptions. Further overridden definitions of this method in subclasses will not be able to throw checked exceptions.
The finalize() method will never be called more than once on an object, even if the finalize() method resurrects the object. An object can be eligible for garbage collection even if there are references denoting the object, as long as the objects owning these references are also eligible for garbage collection. There is no guarantee that the garbage collector will destroy an eligible object before the program terminates. The order in which the objects are destroyed is not guaranteed. The finalize() method can make an object that has been eligible for garbage collection, accessible again by a live thread.
(c), (e), and (f)
Static initializer blocks (a) and (b) are not legal since the fields alive and STEP are non-static and final, respectively. (d) is syntactically not a legal static initializer block.
The program will compile without error and will print 50, 70, 0, 20, 0 when run. All fields are given default values unless they are explicitly initialized. Field i is assigned the value 50 in the static initializer block that is executed when the class is initialized. This assignment will override the explicit initialization of field i in its declaration statement. When the main() method is executed, the static field i is 50 and the static field l is 0. When an instance of the class is created using the new operator, the value of static field l (i.e., 0) is passed to the constructor. Before the body of the constructor is executed, the instance initializer block is executed, which assigns values 70 and 20 to fields j and l, respectively. When the body of the constructor is executed, the fields i, j, k, and l, and the parameter m, have the values 50, 70, 0, 20, and 0, respectively.
This class has a blank final boolean variable active. This variable must be initialized when an instance is constructed or else the code will not compile. The keyword static is used to signify that a block is a static initializer block. No keyword is used to signify that a block is an instance initializer block. (a) and (b) are not instance initializers blocks, and (c), (d), and (e) fail to initialize the blank final variable active.
The program will compile without error and will print 2, 3, and 1 when run. When the object is created and initialized, the instance initializer block is executed first, printing 2. Then the instance initializer expression is executed, printing 3. Finally, the constructor body is executed, printing 1. The forward reference in the instance initializer block is legal, as the use of the field m is on the left-hand side of the assignment.
The program will compile without error and will print 1, 3, and 2 when run. First, the static initializers are executed when the class is initialized, printing 1 and 3. When the object is created and initialized, the instance initializer block is executed, printing 2.
(c) and (e)
Line A will cause illegal redefinition of the field width. Line B uses an illegal forward reference to the fields width and height. The assignment in line C is legal. Line D is not a legal initializer since it is neither a declaration nor a block. Line E declares a local variable inside an initializer block.