The Object Class

   

The Object Class

The java.lang.Object class sits at the root of the Java class hierarchy and is therefore a superclass of every class you create. Object is unique in that it is the only class in Java without a superclass. The methods implemented by Object provide a framework for several general-purpose operations. You saw one of these methods, the toString() method, earlier in the StopLightColor class (refer to Listing 7.5). You can override toString() in the classes you declare to define a text representation of a class instance. Whenever your program has a need to display a value for an object, toString() is called to find out what to display. This is how a method such as System.out.println() can accept an Object as a parameter in place of a string. In this case, the text sent to the console is the return value from the object's toString() method.

The usefulness of toString() is also evident when you are building a Swing application. Instead of looping through a set of objects and manually populating a component such as a JList with strings that represent each instance, you can add the objects themselves to the list and let the component do the work for you. When this type of Swing component needs to display its entries, it makes calls to the toString() methods of the objects without requiring you to do anything. The use of toString() also ensures that objects are always represented the same way when they are displayed in this manner. The Object class provides a default implementation for toString(), but you should normally override this to make the returned string more meaningful.

Object Equality

When two objects are compared using the == operator, the comparison is actually a test of whether the two object references are pointing to the same object. The equals() method defined in Object performs this same comparison, but the intent is to allow you to override this method and provide your own definition of equality for a given class. The equals() method is commonly overridden to return true if two objects are of the same class type and have equivalent values for each instance field.

Copying a Class Instance

The fact that Java always works with objects by reference complicates the issue of copying an object to some degree. Consider the following example:

 Circle firstCircle = new Circle(); Circle secondCircle = firstCircle; 

The execution of these two statements creates a single Circle object with two references, firstCircle and secondCircle, pointing to it. The assignment of firstCircle to secondCircle does not copy the state of the Circle referred to by firstCircle into a second instance; it copies a reference to the single object that exists. To copy an object, you use the clone() method defined in the Object class:

 Circle firstCircle = new Circle(); Circle secondCircle = (Circle)firstCircle.clone(); 

Now, the execution of these modified statements results in two unique objects having the same state. The implementation might seem simple, but there are some other details under the hood to consider. First, the clone() method defined in Object performs a simple byte-by-byte shallow copy. Because the purpose of clone() is to duplicate the state of an object, this copying process is not preceded by the invoking of a constructor or any initializer blocks. A shallow copy is sufficient in the example here, but, if Circle were a more complicated class that included references to other objects, its class declaration would have to override clone() to provide a suitable deep-copy implementation. Also, Circle must be declared to implement the Cloneable marker interface (see Chapter 9). This restriction prevents clone() from being called for a class that the programmer has not explicitly stated can support the operation correctly.

Note

A shallow copy of an object produces a copy of its primitive attributes and its references to other objects, but it does not create copies of those referenced objects. A deep copy produces copies of the referenced objects, any objects they reference, and so on until all the references are exhausted.


Cleaning Up in the finalize() Method

Although Java classes do not need a destructor to free allocated memory, there is support for cleaning up any associated resources before an object is garbage collected. The Object class defines a finalize() method for this purpose. Empty by default, this method is called by the Java runtime system during the process of garbage collection and can be used to clean up any ongoing processes before the object is destroyed . For example, in a class that deals with sockets, it is a good practice to close all sockets opened by an object before it is de stroyed. You could place the code to close the sockets in an overridden version of the finalize() method that would be invoked when the instance is no longer being used in the program.

For example, take a look at the finalize() method in Listing 7.10.

Listing 7.10 NetworkSender.java ” Using finalize()
 import java.io.*; import java.net.*; public class NetworkSender {   private Socket me;   private OutputStream out;   public NetworkSender(String host, int port) {     try {       me = new Socket(host,port);       out = me.getOutputStream();     }     catch (Exception e) {       System.out.println(e.getMessage());     }   }   public void sendInfo(char signal) {     try {       out.write(signal);       out.flush();     }     catch (Exception e) {       System.out.println(e.getMessage());     }   }   public void disconnect() {     System.out.println("Disconnecting...");     try {       me.close();     }     catch (Exception e) {       System.out.println("Error on Disconnect" + e.getMessage());     }     System.out.println("done.");    }   // override finalize() to make sure the socket is closed   protected void finalize() {     disconnect();     try {       super.finalize();     }     catch (Throwable t) {       t.printStackTrace();     }   } } 

Note

finalize() is declared to be protected in java.lang.Object, so it must remain protected or become less restricted. Unlike the case of constructors, the compiler does not automatically insert calls to superclass finalize() methods. These calls must be explicitly coded as shown previously in Listing 7.10.


Caution

Although the finalize() method is a legitimate tool, it should not be relied upon too heavily because garbage collection is not a predictable process. Garbage collection runs in the background as a low-priority thread and might occur only when a program has totally run out of memory. Consequently, it is a good practice to perform such clean-up tasks elsewhere in your code.


   


Special Edition Using Java 2 Standard Edition
Special Edition Using Java 2, Standard Edition (Special Edition Using...)
ISBN: 0789724685
EAN: 2147483647
Year: 1999
Pages: 353

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net