Saturday, 23 July 2016

Beginning Java Programming Chapter-4

Organizing Your Java Application

A Java application is composed of a set of files generally distributed in a directory structure. This set of files may comprise groups of files, called packages, based on their functionalities. Here are some bare-bones facts about these files:
• The files that contain the original source code are called source files and have the extension .java . All the code goes into classes, which are defined inside the .java files.
• When you compile a .java file, it produces a .class file corresponding to each class declared (defined) in the .java file, including nested classes and interfaces.
• The .class file has the same name as the class in the .java file to which it corresponds.
• The compiler searches for a class file when it encounters a reference to a class in a .java file. Similarly, the interpreter, during runtime, searches the .class files.
• Both the compiler and the interpreter search for the .class files in the list of directories listed in the classpath variable. In order to compile and execute an application correctly, you need to understand the relationship between the class name, classpath , and package name and how these three elements determine the directory structure in which you are supposed to store the .class files.
We cover all of these concepts in this section. Let's begin by identifying the point in your application where the execution starts.
Entering Through the Main Gate
When you issue a command to execute a Java application, the Java virtual machine (JVM) loads the class mentioned in the command, and invokes the main(…) method of this class. In other words, the main(…) method of a class in a Java application is the starting point for the execution control. You write the application by writing the Java source ( .java ) files. A source file may contain interfaces or classes. One of the classes in the application must have the main(…) method with the signature:
public static void main (String[] args) {
}
The method main(…) must be declared public , static , and void . These keywords are explained here:
• public : The method can be accessed from the code outside the class in which it is defined (remember, it is invoked by the JVM, which exists outside the class in which it is defined).
• static : The method can be accessed without instantiating the class in which it is declared. Again, this keyword also allows the JVM to invoke this method without instantiating the class.
• void : The method does not return any data. A source file may have one or more classes defined in it. Out of these classes, only one class at most may be declared public . If there is one class declared public in the file, then the file name must match the name of this public class. When the source file is compiled, it generates one class file (a file with the .class extension) corresponding to each class in the source file. The name of the generated class file matches the name of the corresponding class in the source file. The parameter of type array in the main(…) method indicates that you can pass arguments to this method. You provide those arguments in the command line when you execute the application by specifying the class that contains the main(…) method.
For example
1. public class TestArgs {
2. public static void main (String [] args) {
3. System.out.println("Length of arguments array: " + args.length);
4. System.out.println("The first argument: " + args[0]);
5. System.out.println("The second argument: " + args[1]);
6. }
7. }
The Result Will Be : Length of arguments array: 2 , The first argument: Ruth, The second argument: Srilatha
The file name of the file in which the class Student exists will be Student.java , which will exist inside a directory named course , which may exist anywhere on the file system. The qualified name for the class is course.Student , and the path name to it is course/Student.java . You can use this class in the code by specifying its qualified name, as in this example:
course.Student student1 = new course.Student();
However, it is not convenient to use the qualified name of a class over and over again. The solution to this problem is to import the package in which the class exists, and use the simple name for the class, as shown here: import course.Student;
You place the import statement in the file that defines the class in which you are going to use the Student class. The import statement must follow any package statement and must precede the first class defined in the file. After you have imported the package this way, you can use the Student class by its simple name: Student student1 = new Student();
You can import all the classes in the package by using the wildcard character * : import course.*;
However, you cannot use the wildcard character in specifying the names of the classes. For example, the following statement to refer to the class Student will generate a compiler error: import course.Stud*;
You can have more than one import statement in a .java file. Bundling related classes and interfaces into a package offers the following advantages:
• It makes it easier to find and use classes.
• It avoids naming conflicts. Two classes with the same name existing in two different packages do not have a name conflict, as long as they are referenced by their fully qualified name.
• It provides access control. You will learn more about access control when access modifiers are discussed later in this chapter.
So, the files in a directory may be composed into a package by the declaration with keyword package :
package <PackageName>;
Then you may use this package in another file by the statement with keyword import :
import <PackageName>;
In a file, package declaration must precede the import statement, which must precede the class
definition. For example, the .java file with the following code will not compile because the import
statement appears before the package statement:
import otherPackage;
package thisPackage;
class A { }
Passing a Primitive Variable When a primitive variable is passed as an argument in a method call, only the copy of the original variable is passed. Therefore any change to the passed variable in the called method will not affect the variable in the calling method. As an example, An integer variable score is defined in the main(…) method (line 3) and is passed as an argument in a method call to the modifyStudent(…) method (line 5). The value of the passed variable is changed in the called method (line 9).
1. class Student {
2. public static void main (String [] args) {
3. int score = 75;
4. Student st = new Student();
5. st.modifyStudent(score);
6. System.out.println("The original student score: " + score);
7. }
8. void modifyStudent(int i){
9. i = i+10;
10. System.out.println("The modified student score: " + i);
11. }
12.}
The output from the execution of Listing 4-4 follows: The modifed student score: 85 , The original student score: 75
This demonstrates that the change in value of the passed variable in the called method did not affect the value of the original variable in the calling method. What if we pass a reference variable as an argument in a method call?
Passing a Reference Variable
When you pass a reference variable in a method, you pass a copy of it and not the original reference variable. Because the copy of the reference variable points to the same object to which the original variable points, the called method can change the object properties by using the passed reference. Now, changing the object and the reference to the object are two different things, so note the following:
• The original object can be changed in the called method by using the passed reference to the object.
• However, if the passed reference itself is changed in the called method, for example, set to null or reassigned to another object, it has no effect on the original reference variable in the calling method. After all, it was a copy of the original variable that was passed in.
As an example,
1. class TestRefVar {
2. public static void main (String [] args) {
3. Student st = new Student("John", 100);
4. System.out.println("The original student info:");
5. System.out.println("name: " + st.getName() + " score: " +
6. st.getScore());
7. TestRefVar tr = new TestRefVar();
8. tr.modifyRef(st);
9. System.out.println("The modified student info in the calling method:");
10. System.out.println("name: " + st.getName() + " score: " + st.getScore());
11. }
12. void modifyRef(Student student){
13. student.setScore(50);
14. student = new Student("Mary", 75);
15. System.out.println("The modified student info in the called method:");
16. System.out.println("name: " + student.getName() + " score: " +
student.getScore());
17. }
18. }
19. class Student {
20. int score;
21. String name;
22. Student(String st, int i){
23. score=i;
24. name=st;
25. }
26. String getName(){
27. return name;
28. }
29. int getScore(){
30. return score;
31. }
32. void setScore(int i){
33. score = i;
34. }
35.}
The following is the output The original student info: name: John score: 100
The modified student info in the called method: name: Mary score: 75
The modified student info in the calling method: name: John score: 50
Using Access Modifiers Access modifiers, also called visibility modifiers, determine the accessibility scope of the Java elements they modify. If you do not explicitly use an access modifier with a Java element, the element implicitly has the default access modifier. The explicit access modifiers may be used with a class and its members (that is, instance variables and methods). They cannot be used with the variables inside a method.
The Java language offers three explicit access modifiers, public , protected , and private , and a default modifier , which is enforced when you do not specify a modifier.
The public Modifier The public modifier makes a Java element most accessible. It may be applied to classes and to their members (that is, instance variables and methods). A class, variable, or method, declared as public , may be accessed from anywhere in the Java application. For example, you declare the main(…) method of any application public so that it may be invoked from any Java runtime environment.
Other public methods may be called from anywhere inside the application. However, generally speaking, it is not a good object-oriented programming practice to declare the instance variables public . If you declare them public , they could be accessed directly, whereas they should always be accessed through the class methods. For example, consider the code fragment
1. class MyClass {
2. public int myNumber = 10;
3. public int getMyNumber(){
4. return myNumber;
5. }
6. }
7. class InstanceTest {
8. public static void main(String[] args) {
9. MyClass mc = new MyClass();
10. System.out.println (" The value of myNumber is " + mc.myNumber);
11. System.out.println (" The value returned by the method is " +
mc.getMyNumber());
12. }
13. }
The output of the code : The value of myNumber is 10, The value returned by the method is 10
Note that the myNumber variable is directly accessed in line 10, and also accessed using a method in line 11. If you replace the access modifier public with private in line 3 and try to recompile it, line 10 will generate the compiler error because you cannot directly access a private class member from outside the class.
The private Modifier The private modifier makes a Java element (a class or a class member) least accessible. The private modifier cannot be applied to a top-level class. It can be applied only to the members of a top-level class—that is, instance variables, methods, and inner classes. Recall that a class that is not defined inside another class is called a top-level class. A private member of a class may only be accessed
from the code inside the same class in which this member is declared. It can be accessed neither from any other class nor from a subclass of the class in which it is declared.
Not A top-level class cannot be declared private ; it can only be public , or default (that is, no access modifier is specified).
1. class PrivateTest {
2.
3. // public int myNumber = 10;
4. private int myNumber = 10;
5. public int getMyNumber(){
6. return myNumber;
7. }
8. }
9. class SubPrivateTest extends PrivateTest {
10. public void printSomething(){
11. System.out.println (" The value of myNumber is " + this.myNumber);
12. System.out.println (" The value returned by the method is " +
this.getMyNumber());
13. }
14. }
15. class TestPrivateTest{
16. public static void main(String[] args) {
17. SubPrivateTest spt = new SubPrivateTest();
18. spt.printSomething();
19. }
20. }
This code will not compile because line 11 will generate a compiler error. You cannot access a private data variable of the parent class directly, as the private class members are not inherited. If you comment out line 11 and then compile and execute the program, the output of the code will be: The value returned by the method is 10.
by declaring the data variable myNumber private , you have disabled the direct access to it from outside the class in which it is declared, and have enforced the rule that this data variable may only be accessed from inside the class, for example, through the method getMyNumber() . This is a good programming practice in the world of object-oriented programming. The fact that you cannot directly access the private members of a class from its subclass can be looked upon this way: a subclass does not inherit the private members of its parent class. The public and private access modifiers are on the two extremes of access: access from verywhere and access from nowhere outside of the class. There is another access modifier called protected that covers the middle ground between these two extremes.
The protected Modifier The protected modifier makes a class member more accessible than the private modifier would, but still less accessible than public . This modifier may be applied only to class members—that is, the variables, methods, and inner classes—but not to the class itself. A class member declared protected is accessible to the following elements:
• All the classes in the same package that contains the class that owns the protected member.
• All the subclasses of the class that owns the protected member. These subclasses have access even if they are not in the same package as the parent class.
For example, consider these two code fragments:
1. package networking;
2. class Communicator {
3. void sendData() {}
4. protected void receiveData() {}
5. }
1. package internetworking;
2. import networking.*;
3. class Client extends Communicator {
4. void communicate(){
5. receiveData();
6. }
7. }
The class Client is a subclass of the class Communicator . But both classes are in different packages. The method receiveData() is declared protected in the class Communicator . It may be called from the class Client (line 5), even though Communicator and Client are in different packages. This is because Client is a subclass of Communicator .
Note : You cannot specify any modifier for the variables inside a method, and you cannot specify the protected modifier for a top-level class.
The Default Modifier You cannot specify any modifier for the variables inside a method, and you cannot specify the protected modifier for a class. The compiler only tells you what access modifier you cannot specify for a given element; however, it does not require you to specify any access modifier for any element. When you do not specify any access modifier for an element, it is assumed that the access is default.
In other words, there is no keyword default for the default modifier. If an element does not explicitly use any modifier, the default access is implied. It may be applied to a class, a variable, or a method.
nywhere (classes or subclasses) in the same package in which the accessed class exists. As an example, consider the following code fragment:
1. package internetworking;
2. import networking.*;
3. class Client extends Communicator {
4. void communicate(){
5. receiveData();
6. sendData(); // compiler error.
7. }
8. }
Line 6 would generate a compiler error, because the method sendData() is declared default in the class Communicator , which is in a different package:
1. package networking;
2. class Communicator {
3. void sendData() {}
4. protected void receiveData() {}
5. }
Note the difference between the protected modifier and the default modifier. A member with a default access can be accessed only if the accessing class belongs to the same package, whereas a member with the protected modifier can be accessed not only from the same package but also from a different package if the accessing class is a subclass of the accessed class.
The final word about access modifiers: a method may not be overridden to be less accessible. For example, a protected method may be overridden as protected or public , but not as private or default. Recall that overriding a method means reimplementing a method inherited from a class higher in the hierarchy. In a nutshell, you can use access modifiers to protect both variables and methods of a class. The Java language supports four distinct access levels for member variables and methods by offering four access modifiers: private , protected , public , and default (i.e. left unspecified). These access modifiers are summarized in Table below –
Table. Access Level that a Class Has Granted to Other Classes by Using Different Modifiers
Access Modifier Class Subclass Package World
Private Yes No No No
protected Yes Yes Yes No
public Yes Yes Yes Yes
Default Yes No No No
The first column in Table 4-1 specifies the possible access modifiers of a class member. The headings of the other columns identify the elements that are trying to access this member. The value Yes means an element has access to the member with the specified access modifier. For example, the second column indicates that a class always has access to its own members regardless of what access modifier they have. The third column indicates whether the subclasses of the class, regardless of which package they are in, have access to the class members with different modifiers. The fourth column indicates whether another class in the same package as the class in question has access to the class members. The fifth column indicates whether all other classes have access to the class members with different access modifiers. So, the decision to use the modifiers is generally driven by striking a balance between accessibility and security. The underlying effect of any modifier, in general, is to modify (or further specify) the behavior of a class or a class member. The access modifiers specify the access behavior, while there are some non-access modifiers that specify how a class or a class member can be used.
Understanding Usage Modifiers There are some modifiers that are not access modifiers but still modify the way a class or a class member is to be used. Collectively, we call these modifiers the usage modifiers . Some of them, such as final , abstract , and static , may be more familiar than others to a beginner.
The final Modifier The final modifier may be applied to a class, a method, or a variable. It means, in general, that the element is final. The specific meaning slightly depends upon the element it applies to. If the element declared final is a variable, that means the value of the variable is constant, and cannot be changed. If a class is declared final , it means the class cannot be extended, and a final method cannot be
overridden. For example, consider Code. The variable dime in the class Calculator is declared final . Also, the object reference calc in class RunCalculator is declared final . The code lines 11 and 13 will generate compiler errors because they attempt to modify the values of the final variables calc and dime , respectively. However, note that line 12 will compile fine, which shows that the final object reference may be used to modify the value of a non-final variable.
1. class Calculator {
2. final int dime = 10;
3. int count = 0;
4. Calculator (int i) {
5. count = i;
6. }
7. }
8. class RunCalculator {
9. public static void main(String[] args) {
10. final Calculator calc = new Calculator(1);
11. calc = new Calculator(2); // compiler error.
12. calc.count = 2; //ok
13. calc.dime = 11; // compiler error.
14. System.out.println("dime: " + calc.dime);
15. }
16. }
If you comment out lines 11 and 13, the code will compile, and the result of execution will be as follows: dime: 10
If you declare a final method inside a non-final class, it will be legal to extend the class, but you cannot override the final method of the parent class in the subclass. Similarly, you can pass the final variable to a method through arguments, but you cannot change their value even inside the method.
So, the final modifier is related to changing the value of a variable. There is another property of a variable, and that is visibility: from where can you see the value (or a change in value) of a variable?
The static Modifier The static modifier can be applied to variables, methods, and a block of code inside a method. The static elements of a class are visible to all the instances of the class. As a result, if one instance of the class makes a change to a static element, all the instances will see that change. Consider code StaticExample The variable instanceCounter is declared static in line 2, and another variable, counter , is not declared static in line 3. When an instance of the class StaticExample is created, both variables are incremented by one (lines 5 and 6). Each instance has its own copy of the variable counter , but they share the variable instanceCounter . A static variable belongs to the class, and not to a specific instance of the class, and therefore is initialized when the class is loaded. A static variable may be referenced by an instance of the class (lines 13 and 14) in which it is declared, or by the class name itself (line 15).
1. class StaticExample {
2. static int instanceCounter = 0;
3. int counter = 0;
4. StaticExample() {
5. instanceCounter++;
6. counter++;
7. }
8. }
9. class RunStaticExample {
10. public static void main(String[] args) {
11. StaticExample se1 = new StaticExample();
12. StaticExample se2 = new StaticExample();
13. System.out.println("Value of instanceCounter for se1: " +
se1.instanceCounter);
14. System.out.println("Value of instanceCounter for se2: " +
se2.instanceCounter);
15. System.out.println("Value of instanceCounter: " +
StaticExample.instanceCounter);
16. System.out.println("Value of counter for se1: " + se1.counter);
17. System.out.println("Value of counter for se2: " + se2.counter);
18. }
19.}
The following is the output from the Code :
Value of instanceCounter for se1: 2
Value of instanceCounter for se2 2
Value of instanceCounter: 2
Value of counter for se1: 1
Value of counter for se2 1
¦ Note A static method cannot access the non-static variables and methods of the class in which it is defined. Also, a static method cannot be overridden as non-static.
remember these points about the static modifier:
• The static elements (variables, methods, and code fragments) belong to the class and not to a particular instance of the class.
• Any change in a static variable of a class is visible to all the instances of the class.
• A static variable is initialized at class load time. Also, a static method and a static code fragment are executed at class load time.
• A static method of a class cannot access the non-static members of the class.
• You cannot declare the following elements as static : constructor, class (that is, the top-level class), interface, inner class (the top-level nested class can be declared static ), inner class methods and instance variables, and local variables.
• It is easier to remember what you can declare static : top-level class members (methods and variables), the top-level nested class, and code fragments.
The static modifier cannot be applied to a top-level class or a class constructor. However, you can apply the final modifier to a class, which means the class cannot be extended. You may face the opposite situation, where you want the class to be extended before it can be instantiated. This situation is handled by the abstract modifier.
The abstract Modifier The abstract modifier may be applied to a class or a method, but not to a variable. A class that is declared abstract cannot be instantiated. Instantiation of an abstract class is not allowed, because it is not fully implemented yet. There is a relationship between an abstract class and an abstract method. If a class has one or more abstract methods, it must be declared abstract . A class may have one or more abstract methods in any of the following ways:
• The class may have one or more abstract methods originally defined in it.
• The class may have inherited one or more abstract methods from its superclass, and has not provided implementation for all or some of them.
• The class declares that it implements an interface, but does not provide implementation for at least one method in the interface.
In any of the preceding cases, the class must be declared abstract . However, if there is no abstract method in the class, it could still be declared abstract . Even in this case, it cannot be instantiated, obviously.
¦ Note A class with one or more abstract methods must be declared abstract . However, a class with no abstract method may also be declared abstract . An abstract class cannot be instantiated.
The native Modifier In your applications, sometimes you will want to use a method that exists outside of the JVM. In this case, the native modifier can help you. The native modifier can only apply to a method. Like abstract , the keyword native indicates that the implementation of the method exists elsewhere. In case of abstract , the implementation may exist in a subclass of the class in which the abstract method is
declared. In case of native , the implementation of the method exists in a library outside of the JVM. The native method is usually implemented in a non-Java language such as C or C++. Before a native method can be invoked, a library that contains the method must be loaded. The library is loaded by making the following system call:
System.loadLibrary("<libraryName>");
For example, the following code fragment presents an example of loading a library named NativeMethodsLib that contains a method (function) named myNativeMethod() :
1. class MyNativeExample {
2. native void myNativeMethod();
3. static {
4. System.loadLibrary("NativeMethodLib");
5. }
6. }
Notice that the library is loaded in a static code block (lines 3 to 5 ). Therefore, the library is loaded at the class load time, so it is there when a call to the native method is made. You can use the native method in the same way as you use a non-native method. For example, the following two lines of code would invoke the native method:
MyNativeExample myNative = new MyNativeExample();
myNative.myNativeMethod();
The native modifier applies only to methods, while another modifier called transient applies only to variables.
The transient Modifier When an application is running, the objects live in the random access memory (RAM) of the computer. This limits the scope and life of the object. However, an object may be stored in persistent storage (say disk) outside of the JVM, for later use by the same application, or by a different application. The process of storing an object is called serialization . For an object to be serializable, the
corresponding class must implement the interface Serializable , or Externalizable .
So, the transient modifier is related to storing an object on the disk. Such storage is called the object's persistent state . A variable declared transient is not stored, and hence does not become part of the object's persistent state. One use of transient is to prevent a security-sensitive piece of data from copying to a file where there is no security mechanism in effect.
The transient modifier can only be applied to instance variables. When you are declaring an instance variable transient , you are instructing the JVM not to store this variable when the object in which it is declared is being serialized.
In a multithreaded environment, more than one process may try to access the same class element concurrently. To handle that situation, there are a couple of modifiers that you need to know about.
The Thread-Related Modifiers A computer program may have launched more than one process executing concurrently. This is called multithreaded programming , and you will learn more about it in Chapter 10. But for now, just imagine that if there are more than one process in a program executing concurrently, they may attempt to access a class element at the same time. There are a couple of modifiers that relate to such a situation.
The volatile Modifier Like the transient modifier, the volatile modifier only applies to instance variables. The variables declared volatile are subject to asynchronous modifications. In other words, declaring a variable volatile informs the compiler that this variable may be changed unexpectedly by other parts of the program. So, the compiler takes some special precautions to keep this variable properly updated.
The volatile variables are generally used in multithreaded or multiprocessor environments. The volatile modifier tells the accessing thread that it should synchronize its private copy of the variable with the master copy in the memory.
The synchronized Modifier The synchronized modifier is used in multithreaded programming to control access to critical sections in the program. This modifier is discussed in detail in Chapter 10 in conjunction with threads. You have explored a multitude of modifiers. Let's take a look at the big picture.
summarizes the use of different modifiers by Java classes and class members.
As you have noticed, not all modifiers can be applied to all Java elements such as classes, methods,
and variables. For example, classes cannot be declared private and methods cannot be declared transient or volatile . Table Below summarizes the use of different modifiers by Java classes and class members. Note that the constructors can use only access modifiers and no other type of modifiers. To the contrary, a code block cannot use any explicit access modifier. To be specific, it can only use static or synchronized modifiers.
 
Summary of Modifiers Used by Java Classes and Class Members
Modifier Top-Level Class Variable Method Constructor Code Block
public Yes Yes Yes Yes No
private No Yes Yes Yes No
protected No Yes Yes Yes N/A
Default Yes Yes Yes No No
final Yes Yes Yes No No
static No Yes Yes No Yes
abstract Yes No Yes No No
native No No Yes No No
transient No Yes No No No
volatile No Yes No No No
synchronized No No Yes No Yes
All of these modifiers are specified with different Java elements in a Java application. Applications running on a computer use memory, which makes memory management a significant issue for any programming language. Because Java is a relatively high-level language, the memory management in Java is automatic. However, to make it more efficient, you need to understand garbage collection —that is, freeing memory from objects that are no longer in use.
Understanding Garbage Collection in Java When you create an object by instantiating a class, the object is put on the heap; in other words, it uses some memory. A Java application creates and uses objects. After an object in memory has been used and is no longer needed, it is sensible to free memory from that object. The process of freeing memory from the used objects is called garbage collection . How do you accomplish this in Java? In Java, garbage collection is done automatically by what is called the garbage collector .
Understanding the Garbage Collector The garbage collector in Java automates memory management by freeing up the memory from objects that are no longer in use. The advantage of this is that you do not need to code the memory management into your application. The price you pay for this service is that you have no control over when the garbage collector runs. There are two things that you can do in the code to help memory management:
• Make an object eligible for garbage collection, because a garbage collector will only free up memory from an eligible object.
• Make a request for garbage collection by making a system call to the garbage collector: System.gc(); .
You can also invoke the gc() method by using an instance of the Runtime class that a running application always has. You get hold of this instance by calling the static method getRuntime() of the Runtime class:
Runtime rt = Runtime.getRuntime();
Then, you can use this instance to invoke methods in order to perform some runtime tasks, such as to get memory information or to run the garbage collector:
rt.gc();
rt.getTotalMemory() // Returns the total amount of memory allocated to the JVM.
rt.freeMemory() // Returns the amount of free JVM memory.
class RuntimeTest {
2. public static void main (String [] args) {
3. Runtime rt = Runtime.getRuntime();
4. System.out.println("JVM free memory before running gc: " + rt.freeMemory());
5. rt.gc();
6. System.out.println("JVM free memory after running gc: " + rt.freeMemory());
7. }
8. }
Remember that an application cannot create its own instance of the Runtime class. Therefore the following code will be invalid:
new Runtime().gc();
A call to the garbage collector is no guarantee that the memory will be free. It is possible, for example, that the JVM in which your program is running did not even implement the gc() method. The Java language specification allows a dummy gc() method.
The basic requirement for garbage collection is that you must make your object eligible for garbage collection. An object is considered eligible for garbage collection when there is no reference pointing to it. You can remove the references to an object in two ways:
• Set the object reference variable pointing to the object to null ; for example: myObject = null;
• Reassign a reference variable of an object to another object. For example, if a reference variable myObject is pointing to an object of the MyClass class, you can free this object from this reference by pointing the reference to another object:
myObject = new YourClass();
Now, the object reference myObject is pointing to an object of the class YourClass and not to an
object of MyClass , to which it was pointing previously.
What if you want an object to clean up its state before it is deleted? Well, you can declare the finalize() method in the class, and this method will be called by the garbage collector before deleting any object of this class.
The finalize() Method
The object that has no object references pointing to it can be deleted by the garbage collector to reclaim the memory. If the object has a finalize() method, it will be executed before reclaiming the memory in order to give the object a last chance to clean up after itself—for example, to release the resources that the object was using. The finalize() method is inherited from the Object class by any class you define. The signature of the finalize() method in the object class is shown here: protected void finalize()
You can override this method in your class. The Java programming language specifies that the finalize() method will be called before the object memory is reclaimed, but it does not guarantee exactly when it will happen. Remember that the finalize() method that your class inherited does not do anything. If you want your object to clean up after itself, you have to override the finalize() method. Then, what is the point of putting the finalize() method in the Object class? It makes it safe for the finalize() method of any class to invoke the finalize() of the superclass, as shown here:
protected void finalize() {
super.finlaize();
// clean up code follows.
}
This is generally a good practice.
When an object is instantiated from a class, it is called reachable and unfinalized . When no reference is pointing to an object, the object can only be reached by the finalize() method, and hence it is called finalizer reachable . However, it is possible to make the object reachable again for any live thread by creating a reference to this object in its finalize() method. The finalize() method for an object is only run once. If you make an object ineligible for garbage collection in its finalize() method, it does not mean that the object will never be garbage collected because its finalize() method now will never be called. The object can still become eligible for garbage collection when it has no reference pointing to it. The only difference is that, this time, the garbage collector will remove it without calling its finalize() method, because it has already been called. The garbage collector is not guaranteed to be invoked, and thus the finalize() method is not guaranteed to be called. It is a good practice for you, the programmer, to free up the resources when they are no longer required.

Beginning Java Programming Chapter 5

No comments:

Post a Comment