Tuesday 21 March 2017

Using clone( ) and the Cloneable Interface, Class & ClassLoader - Java Tutorials

Using clone( ) and the Cloneable Interface

Most of the methods defined by Object are discussed elsewhere in this book. However, one deserves special attention: clone( ). The clone( ) method generates a duplicate copy of the object on which it is called. Only classes that implement the Cloneable interface can be cloned.

The Cloneable interface defines no members. It is used to indicate that a class allows a bitwise copy of an object (that is, a clone) to be made. If you try to call clone( ) on a class that does not implement Cloneable, a CloneNotSupportedException is thrown. When a clone is made, the constructor for the object being cloned is not called. A clone is simply an exact copy of the original.


The Methods Defined by Object

Object clone( ) throws CloneNotSupportedException:   Creates a new object that is the same as the invoking object.

boolean equals(Object object):  Returns true if the invoking object is equivalent to object.

void finalize( ) throws Throwable:   Default finalize( ) method. This is usually overridden by subclasses.

final Class getClass( ):  Obtains a Class object that describes the invoking object.

int hashCode( ):  Returns the hash code associated with the invoking object.

final void notify( ):  Resumes execution of a thread waiting on the invoking object.

final void notifyAll( ):  Resumes execution of all threads waiting on the invoking object.

String toString( ):  Returns a string that describes the object.

final void wait( ) throws InterruptedException:   Waits on another thread of execution.

final void wait(long milliseconds) throws InterruptedException:   Waits up to the specified number of milliseconds on another thread of execution.

final void wait(long milliseconds, int nanoseconds) throws InterruptedException:  Waits up to the specified number of milliseconds plus nanoseconds on another thread of execution.


Cloning is a potentially dangerous action, because it can cause unintended side effects. For example, if the object being cloned contains a reference variable called obRef, then when the clone is made, obRef in the clone will refer to the same object as does obRef in the original. If the clone makes a change to the contents of the object referred to by obRef, then it will be changed for the original object, too. Here is another example. If an object opens an I/O stream and is then cloned, two objects will be capable of operating on the same stream. Further, if one of these objects closes the stream, the other object might still attempt to write to it, causing an error.

Because cloning can cause problems, clone( ) is declared as protected inside Object. This means that it must either be called from within a method defined by the class that implements Cloneable, or it must be explicitly overridden by that class so that it is public. Let’s look at an example of each approach.

The following program implements Cloneable and defines the method cloneTest( ), which calls clone( ) in Object:

  // Demonstrate the clone() method.
  
  class TestClone implements Cloneable {
    int a;
    double b;

    // This method calls Object's clone().
    TestClone cloneTest() {
      try {
        // call clone in Object.
        return (TestClone) super.clone();
      } catch(CloneNotSupportedException e) {
        System.out.println("Cloning not allowed.");
        return this;
      }
    }
  }

  class CloneDemo {
    public static void main(String args[]) {
      TestClone x1 = new TestClone();
      TestClone x2;

      x1.a = 10;
      x1.b = 20.98;

      x2 = x1.cloneTest(); // clone x1

      System.out.println("x1: " + x1.a + " " + x1.b);
      System.out.println("x2: " + x2.a + " " + x2.b);
    }
  }

Here, the method cloneTest( ) calls clone( ) in Object and returns the result. Notice that the object returned by clone( ) must be cast into its appropriate type (TestClone). The following example overrides clone( ) so that it can be called from code outside of its class. To do this, its access specifier must be public, as shown here:

  // Override the clone() method.

  class TestClone implements Cloneable {
    int a;
    double b;

    // clone() is now overridden and is public.
    public Object clone() {
      try {
        // call clone in Object.
        return super.clone();
      } catch(CloneNotSupportedException e) {
        System.out.println("Cloning not allowed.");
        return this;
      }
    }
  }

  class CloneDemo2 {
    public static void main(String args[]) {
      TestClone x1 = new TestClone();
      TestClone x2;

      x1.a = 10;
      x1.b = 20.98;

      // here, clone() is called directly.
      x2 = (TestClone) x1.clone();

      System.out.println("x1: " + x1.a + " " + x1.b);
      System.out.println("x2: " + x2.a + " " + x2.b);
    }
  }

The side effects caused by cloning are sometimes difficult to see at first. It is easy to think that a class is safe for cloning when it actually is not. In general, you should not implement Cloneable for any class without good reason.




Class

Class encapsulates the run-time state of an object or interface. Objects of type Class are created automatically, when classes are loaded. You cannot explicitly declare a Class object. Generally, you obtain a Class object by calling the getClass( ) method defined by Object.


Some Methods Defined by Class

static Class forName(String name) throws ClassNotFoundException:   Returns a Class object given its complete name.

static Class forName(String name, boolean how, ClassLoader ldr) throws ClassNotFoundException:  Returns a Class object given its complete name. The object is loaded using the loader specified by ldr. If how is true, the object is initialized; otherwise it is not. (Added by Java 2)

Class[ ] getClasses( ):  Returns a Class object for each of the public classes and interfaces that are members of the invoking object.

ClassLoader getClassLoader( ):  Returns the ClassLoader object that loaded the class or interface used to instantiate the invoking object.

Constructor[ ] getConstructors( ) throws SecurityException:   Returns a Constructor object for all the public constructors of this class.

Constructor[ ] getDeclaredConstructors( ) throws SecurityException:  Returns a Constructor object for all the constructors that are declared by this class.

Field[ ] getDeclaredFields( ) throws SecurityException:   Returns a Field object for all the fields that are declared by this class.

Method[ ] getDeclaredMethods( ) throws SecurityException:   Returns a Method object for all the methods that are declared by this class or interface.

Field[ ] getFields( ) throws SecurityException:   Returns a Field object for all the public fields of this class.

Class[ ] getInterfaces( ):   When invoked on an object, this method returns an array of the interfaces implemented by the class type of the object. When invoked on an interface, this method returns an array of interfaces extended by the interface.

Method[ ] getMethods( ) throws SecurityException:   Returns a Method object for all the public methods of this class.

String getName( ):   Returns the complete name of the class or interface of the invoking object.

ProtectionDomain getProtectionDomain( ):   Returns the protection domain associated with the invoking object. (Added by Java 2)

Class getSuperclass( ):   Returns the superclass of the invoking object. The return value is null if the invoking object is of type Object.

boolean isInterface( ):   Returns true if the invoking object is an interface. Otherwise, it returns false.

Object newInstance( ) throws IllegalAccessException, InstantiationException:  Creates a new instance (i.e., a new object) that is of the same type as the invoking object. This is equivalent to using new with the class’ default constructor. The new object is returned.

String toString( ):   Returns the string representation of the invoking object or interface.


The methods defined by Class are often useful in situations where run-time type information about an object is required. As Table 14-13 shows, methods are provided that allow you to determine additional information about a particular class, such as its public constructors, fields, and methods. This is important for the Java Beans functionality, which is discussed later in this book.

The following program demonstrates getClass( ) (inherited from Object) and getSuperclass( ) (from Class):

  // Demonstrate Run-Time Type Information.

  class X {
    int a;
    float b;
  }

  class Y extends X {
    double c;
  }
  
  class RTTI {
    public static void main(String args[]) {
      X x = new X();
      Y y = new Y();
      Class clObj;

      clObj = x.getClass(); // get Class reference
      System.out.println("x is object of type: " +
                         clObj.getName());

      clObj = y.getClass(); // get Class reference
      System.out.println("y is object of type: " +
                         clObj.getName());
      clObj = clObj.getSuperclass();
      System.out.println("y's superclass is " +
                         clObj.getName());
    }
  }

The output from this program is shown here:

  x is object of type: X
  y is object of type: Y
  y’s superclass is X




ClassLoader

The abstract class ClassLoader defines how classes are loaded. Your application can create subclasses that extend ClassLoader, implementing its methods. Doing so allows you to load classes in some way other than the way they are normally loaded by the Java run-time system.


Some of the Methods Defined by ClassLoader

final Class defineClass(String str, byte b[ ], int index, int numBytes) throws ClassFormatError:  Returns a Class object. The name of the class is in str and the object is contained in the array of bytes specified by b. The object begins within this array at the index specified by index and is numBytes long. The data in b must represent a valid object.

final Class findSystemClass(String name) throws ClassNotFoundException:   Returns a Class object given its name.

Class loadClass(String name, boolean callResolveClass) throws ClassNotFoundException:  An implementation of this abstract method must load a class given its name and call resolveClass( ) if callResolveClass is true.

final void resolveClass(Class obj):   The class referred to by obj is resolved (i.e., its name is entered into the class name space).

No comments:

Post a Comment