Making local copies | CodeGuru

Making local copies

Bruce Eckel’s Thinking in Java Contents | Prev | Next To review: all argument passing in Java is performed by passing handles. That is, when you pass “an object,” you’re really passing only a handle to an object that lives outside the method, so if you perform any modifications with that handle, you modify the […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
15 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

To


review: all argument passing in Java is performed by passing handles. That is,


when you pass “an object,” you’re really passing only a


handle to an object that lives outside the method, so if you perform any


modifications with that handle, you modify the outside object. In addition:

  • Aliasing
    happens automatically during argument passing.
  • There
    are no local objects, only local handles.
  • Handles
    have scopes, objects do not.
  • Object
    lifetime is never an issue in Java.
  • There
    is no language support (e.g. const) to prevent objects from being modified (to
    prevent negative effects of aliasing).

If


you’re only reading information from an object and not modifying it,


passing a handle is the most efficient form of argument passing. This is nice;


the default way of doing things is also the most efficient. However, sometimes


it’s necessary to be able to treat the object as if it were


“local” so that changes you make affect only a local copy and do


not modify the outside object. Many programming languages support the ability


to automatically make a local copy of the outside object, inside the method.


[49]

Java does not, but it allows you to produce this effect.


Pass
by value

This


brings up the terminology issue, which always seems good for an argument. The


term is “

pass
by value,” and the meaning depends on how you perceive the operation of
the program. The general meaning is that you get a local copy of whatever
you’re passing, but the real question is how you think about what
you’re passing. When it comes to the meaning of “pass by
value,” there are two fairly distinct camps:
  1. Java
    passes everything by value. When you’re passing primitives into a method,
    you get a distinct copy of the primitive. When you’re passing a handle
    into a method, you get a copy of the handle. Ergo, everything is pass by value.
    Of course, the assumption is that you’re always thinking (and caring)
    that handles are being passed, but it seems like the Java design has gone a
    long way toward allowing you to ignore (most of the time) that you’re
    working with a handle. That is, it seems to allow you to think of the handle as
    “the object,” since it implicitly dereferences it whenever you make
    a method call.
  2. Java
    passes primitives by value (no argument there), but objects are passed by
    reference. This is the world view that the handle is an alias for the object,
    so you
    don’t
    think about passing handles, but instead say “I’m passing the
    object.” Since you don’t get a local copy of the object when you
    pass it into a method, objects are clearly not passed by value. There appears
    to be some support for this view within Sun, since one of the “reserved
    but not implemented” keywords is
    byvalue.
    (There’s no knowing, however, whether that keyword will ever see the
    light of day.)

Having


given both camps a good airing and after saying “It depends on how you


think of a handle,” I will attempt to sidestep the issue for the rest of


the book. In the end, it isn’t


that

important – what is important is that you understand that passing a


handle allows the caller’s object to be changed unexpectedly.


Cloning
objects

The


most likely reason for making a local copy of an object is if you’re


going to modify that object and you don’t want to modify the


caller’s object. If you decide that you want to make a local copy, you


simply use the


clone( )

method to perform the operation. This is a method that’s defined as


protected

in


the base class


Object

and which you must override as


public

in


any derived classes that you want to clone. For example, the standard library


class


Vector

overrides


clone( )

,


so we can call


clone( )

for


Vector

:

//: Cloning.java
// The clone() operation works for only a few
// items in the standard Java library.
import java.util.*;
 
class Int {
  private int i;
  public Int(int ii) { i = ii; }
  public void increment() { i++; }
  public String toString() {
    return Integer.toString(i);
  }
}
 
public class Cloning {
  public static void main(String[] args) {
    Vector v = new Vector();
    for(int i = 0; i < 10; i++ )
      v.addElement(new Int(i));
    System.out.println("v: " + v);
    Vector v2 = (Vector)v.clone();
    // Increment all v2's elements:
    for(Enumeration e = v2.elements();
        e.hasMoreElements(); )
      ((Int)e.nextElement()).increment();
    // See if it changed v's elements:
    System.out.println("v: " + v);
  }
} ///:~ 

The


clone( )

method produces an


Object

,


which must then be recast to the proper type. This example shows how


Vector

’s


clone( )

method


does
not

automatically try to clone each of the objects that the


Vector

contains – the old


Vector

and the cloned


Vector

are aliased to the same objects. This is often called a

shallow
copy
,
since it’s copying only the “surface” portion of an object.
The actual object consists of this “surface” plus all the objects
that the handles are pointing to, plus all the objects
those
objects
are pointing to, etc. This is often referred to as the “
web
of objects.” Copying the entire mess is called a
deep
copy
.

You


can see the effect of the shallow copy in the output, where the actions


performed on


v2

affect


v

:

v: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
v: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Not


trying to


clone( )

the


objects contained in the


Vector

is


probably a fair assumption because there’s no guarantee that those objects


are

cloneable.


[50]

Advertisement

Adding
cloneability to a class

Even


though the clone method is defined in the base-of-all-classes


Object

,


cloning is


not

automatically


available in every class.


[51]

This would seem to be counterintuitive to the idea that base-class methods are


always available in derived classes. Cloning in Java goes against this idea; if


you want it to exist for a class, you must specifically add code to make


cloning work.


Using
a trick with protected

To


prevent default clonability in every class you create, the

clone( )
method is
protected
in the base class
Object.
Not only does this mean that it’s not available by default to the client
programmer who is simply using the class (not subclassing it), but it also
means that you cannot call
clone( )
via a handle to the base class. (Although that might seem to be useful in some
situations, such as to polymorphically clone a bunch of
Objects.)
It is in effect a way to give you, at compile time, the information that your
object is not cloneable – and oddly enough most classes in the standard
Java library are not cloneable. Thus, if you say:
    Integer x = new Integer(1);
    x = x.clone();

You


will get, at compile time, an error message that says


clone( )

is


not accessible (since


Integer

doesn’t override it and it defaults to the


protected

version).

If,


however, you’re in a class derived from


Object

(as


all classes are), then you have permission to call


Object.clone( )

because


it’s

protected
and
you’re an inheritor. The base class
clone( )
has
useful functionality – it performs the actual bitwise duplication
of
the derived-class object
,
thus acting as the common cloning operation. However, you then need to make
your
clone operation
public
for it to be accessible. So two key issues when you clone are: virtually always
call
super.clone( )
and
make your clone
public.

You’ll


probably want to override


clone( )

in


any further derived classes, otherwise your (now


public

)


clone( )

will be used, and that might not do the right thing (although, since


Object.clone( )

makes a copy of the actual object, it might). The


protected

trick works only once, the first time you inherit from a class that has no


clonability and you want to make a class that’s cloneable. In any classes


inherited from your class the


clone( )

method


is available since it’s not possible in Java to reduce the access of a


method during derivation. That is, once a class is cloneable, everything


derived from it is cloneable unless you use provided mechanisms (described


later) to “turn off” cloning.


Implementing
the Cloneable interface

There’s


one more thing you need to do to complete the clonability of an object:


implement the

Cloneable
interface.
This
interface
is a bit strange because it’s empty!
interface
Cloneable {}

The


reason for implementing this empty


interface

is obviously not because you are going to upcast to


Cloneable

and call one of its methods. The use of


interface

here is considered by some to be a “hack” because it’s using


a feature for something other than its original intent. Implementing the


Cloneable
interface

acts as a kind of a flag, wired into the type of the class.

There


are two reasons for the existence of the


Cloneable
interface

.


First, you might have an upcast handle to a base type and not know whether


it’s possible to clone that object. In this case, you can use the


instanceof

keyword (described in Chapter 11) to find out whether the handle is connected


to an object that can be cloned:

if(myHandle
instanceof Cloneable) // ...

The


second reason is that mixed into this design for clonability was the thought


that maybe you didn’t want all types of objects to be cloneable. So


Object.clone( )

verifies that a class implements the


Cloneable

interface. If not, it throws a


CloneNotSupportedException

exception. So in general, you’re forced to


implement
Cloneable

as part of support for cloning.


Successful
cloning

Once


you understand the details of implementing the


clone( )

method, you’re able to create classes that can be easily duplicated to


provide a local copy:

//: LocalCopy.java
// Creating local copies with clone()
import java.util.*;
 
class MyObject implements Cloneable {
  int i;
  MyObject(int ii) { i = ii; }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println("MyObject can't clone");
    }
    return o;
  }
  public String toString() {
    return Integer.toString(i);
  }
}
 
public class LocalCopy {
  static MyObject g(MyObject v) {
    // Passing a handle, modifies outside object:
    v.i++;
    return v;
  }
  static MyObject f(MyObject v) {
    v = (MyObject)v.clone(); // Local copy
    v.i++;
    return v;
  }
  public static void main(String[] args) {
    MyObject a = new MyObject(11);
    MyObject b = g(a);
    // Testing handle equivalence,
    // not object equivalence:
    if(a == b)
      System.out.println("a == b");
    else
      System.out.println("a != b");
    System.out.println("a = " + a);
    System.out.println("b = " + b);
    MyObject c = new MyObject(47);
    MyObject d = f(c);
    if(c == d)
      System.out.println("c == d");
    else
      System.out.println("c != d");
    System.out.println("c = " + c);
    System.out.println("d = " + d);
  }
} ///:~ 

First


of all,


clone( )

must be accessible so you must make it


public

.


Second, for the initial part of your


clone( )

operation you should call the base-class version of


clone( )

.


The


clone( )

that’s being called here is the one that’s predefined inside


Object

,


and you can call it because it’s


protected

and thereby accessible in derived classes.

Object.clone( )

figures out how big the object is, creates enough memory for a new one, and


copies all the bits from the old to the new. This is called a

bitwise
copy
,
and is typically what you’d expect a
clone( )
method to do. But before
Object.clone( )
performs its operations, it first checks to see if a class is
Cloneable,
that is, whether it implements the
Cloneable
interface. If it doesn’t,
Object.clone( )
throws a
CloneNotSupportedException
to indicate that you can’t clone it. Thus, you’ve got to surround
your call to
super.clone( )
with a try-catch block, to catch an exception that should never happen (because
you’ve implemented the
Cloneable
interface).

In


LocalCopy

,


the two methods


g( )

and


f( )

demonstrate the difference between the two approaches for argument passing.


g( )

shows passing by reference in which it modifies the outside object and returns


a reference to that outside object, while


f( )

clones the argument, thereby decoupling it and leaving the original object


alone. It can then proceed to do whatever it wants, and even to return a handle


to this new object without any ill effects to the original. Notice the somewhat


curious-looking statement:

v
= (MyObject)v.clone();

This


is where the local copy is created. To prevent confusion by such a statement,


remember that this rather strange coding idiom is perfectly feasible in Java


because everything that has a name is actually a handle. So the handle


v

is used to


clone( )

a copy of what it refers to, and this returns a handle to the base type


Object

(because it’s defined that way in


Object.clone( )

)


that must then be cast to the proper type.

In


main( )

,


the difference between the effects of the two different argument-passing


approaches in the two different methods is tested. The output is:

a == b
a = 12
b = 12
c != d
c = 47
d = 48

It’s


important to notice that the equivalence tests in Java do not look inside the


objects being compared to see if their values are the same. The

==
and
!=
operators are simply comparing the contents of the
handles.
If the addresses inside the
handles
are the same, the handles are pointing to the same object and are therefore
“equal.” So what the operators are really testing is whether the
handles are aliased to the same object!

Advertisement

The
effect of Object.clone( )

What


actually happens when

Object.clone( )
is called that makes it so essential to call
super.clone( )
when you override
clone( )
in your class? The
clone( )
method in the root class is responsible for creating the correct amount of
storage and making the bitwise copy of the bits from the original object into
the new object’s storage. That is, it doesn’t just make storage and
copy an
Object
– it actually figures out the size of the precise object that’s
being copied and duplicates that. Since all this is happening from the code in
the
clone( )
method defined in the root class (that has no idea what’s being inherited
from it), you can guess that the process involves
RTTI
to determine the actual object that’s being cloned. This way, the
clone( )
method can create the proper amount of storage and do the correct bitcopy for
that type.

Whatever


you do, the first part of the cloning process should normally be a call to


super.clone( )

.


This establishes the groundwork for the cloning operation by making an exact


duplicate. At this point you can perform other operations necessary to complete


the cloning.

To


know for sure what those other operations are, you need to understand exactly


what


Object.clone( )

buys you. In particular, does it automatically clone the destination of all the


handles? The following example tests this:

//: Snake.java
// Tests cloning to see if destination of
// handles are also cloned.
 
public class Snake implements Cloneable {
  private Snake next;
  private char c;
  // Value of i == number of segments
  Snake(int i, char x) {
    c = x;
    if(--i > 0)
      next = new Snake(i, (char)(x + 1));
  }
  void increment() {
    c++;
    if(next != null)
      next.increment();
  }
  public String toString() {
    String s = ":" + c;
    if(next != null)
      s += next.toString();
    return s;
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {}
    return o;
  }
  public static void main(String[] args) {
    Snake s = new Snake(5, 'a');
    System.out.println("s = " + s);
    Snake s2 = (Snake)s.clone();
    System.out.println("s2 = " + s2);
    s.increment();
    System.out.println(
      "after s.increment, s2 = " + s2);
  }
} ///:~ 

A


Snake

is made up of a bunch of segments, each of type


Snake

.


Thus, it’s a singly-linked list. The segments are created recursively,


decrementing the first constructor argument for each segment until zero is


reached. To give each segment a unique tag, the second argument, a


char

,


is incremented for each recursive constructor call.

The


increment( )

method recursively increments each tag so you can see the change, and the


toString( )

recursively prints each tag. The output is:

s = :a:b:c:d:e
s2 = :a:b:c:d:e
after s.increment, s2 = :a:c:d:e:f

This


means that only the first segment is duplicated by


Object.clone( )

,


so it does a

shallow
copy. If you want the whole snake to be duplicated – a
deep
copy – you must perform the additional operations inside your overridden
clone( ).

You’ll


typically call


super.clone( )

in any class derived from a cloneable class to make sure that all of the


base-class operations (including


Object.clone( )

)


take place. This is followed by an explicit call to


clone( )

for


every handle in your object; otherwise those handles will be aliased to those


of the original object. It’s analogous to the way constructors are called


– base-class constructor first, then the next-derived constructor, and so


on to the most-derived constructor. The difference is that


clone( )

is not a constructor so there’s nothing to make it happen automatically.


You must make sure to do it yourself.


Cloning
a composed object

There’s


a problem you’ll encounter when trying to deep copy a composed object.


You must assume that the


clone( )

method in the member objects will in turn perform a deep copy on


their

handles, and so on. This is quite a commitment. It effectively means that for a


deep copy to work you must either control all of the code in all of the


classes, or at least have enough knowledge about all of the classes involved in


the deep copy to know that they are performing their own deep copy correctly.

This


example shows what you must do to accomplish a deep copy when dealing with a


composed object:

//: DeepCopy.java
// Cloning a composed object
 
class DepthReading implements Cloneable {
  private double depth;
  public DepthReading(double depth) {
    this.depth = depth;
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
    return o;
  }
}
 
class TemperatureReading implements Cloneable {
  private long time;
  private double temperature;
  public TemperatureReading(double temperature) {
    time = System.currentTimeMillis();
    this.temperature = temperature;
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
    return o;
  }
}
 
class OceanReading implements Cloneable {
  private DepthReading depth;
  private TemperatureReading temperature;
  public OceanReading(double tdata, double ddata){
    temperature = new TemperatureReading(tdata);
    depth = new DepthReading(ddata);
  }
  public Object clone() {
    OceanReading o = null;
    try {
      o = (OceanReading)super.clone();
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
    // Must clone handles:
    o.depth = (DepthReading)o.depth.clone();
    o.temperature =
      (TemperatureReading)o.temperature.clone();
    return o; // Upcasts back to Object
  }
}
 
public class DeepCopy {
  public static void main(String[] args) {
    OceanReading reading =
      new OceanReading(33.9, 100.5);
    // Now clone it:
    OceanReading r =
      (OceanReading)reading.clone();
  }
} ///:~ 
DepthReading

and


TemperatureReading

are quite similar; they both contain only primitives. Therefore, the


clone( )

method can be quite simple: it calls


super.clone( )

and returns the result. Note that the


clone( )

code for both classes is identical.

OceanReading

is composed of


DepthReading

and


TemperatureReading

objects and so, to produce a deep copy, its


clone( )

must clone the handles inside


OceanReading

.


To accomplish this, the result of


super.clone( )

must be cast to an


OceanReading

object (so you can access the


depth

and


temperature

handles).


Advertisement

A
deep copy with Vector

Let’s


revisit the

Vector
example from earlier in this chapter. This time the
Int2
class is cloneable so the
Vector
can be deep copied:
//: AddingClone.java
// You must go through a few gyrations to
// add cloning to your own class.
import java.util.*;
 
class Int2 implements Cloneable {
  private int i;
  public Int2(int ii) { i = ii; }
  public void increment() { i++; }
  public String toString() {
    return Integer.toString(i);
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println("Int2 can't clone");
    }
    return o;
  }
}
 
// Once it's cloneable, inheritance
// doesn't remove cloneability:
class Int3 extends Int2 {
  private int j; // Automatically duplicated
  public Int3(int i) { super(i); }
}
 
public class AddingClone {
  public static void main(String[] args) {
    Int2 x = new Int2(10);
    Int2 x2 = (Int2)x.clone();
    x2.increment();
    System.out.println(
      "x = " + x + ", x2 = " + x2);
    // Anything inherited is also cloneable:
    Int3 x3 = new Int3(7);
    x3 = (Int3)x3.clone();
 
    Vector v = new Vector();
    for(int i = 0; i < 10; i++ )
      v.addElement(new Int2(i));
    System.out.println("v: " + v);
    Vector v2 = (Vector)v.clone();
    // Now clone each element:
    for(int i = 0; i < v.size(); i++)
      v2.setElementAt(
        ((Int2)v2.elementAt(i)).clone(), i);
    // Increment all v2's elements:
    for(Enumeration e = v2.elements();
        e.hasMoreElements(); )
      ((Int2)e.nextElement()).increment();
    // See if it changed v's elements:
    System.out.println("v: " + v);
    System.out.println("v2: " + v2);
  }
} ///:~ 
Int3

is inherited from


Int2

and a new primitive member


int
j

is


added. You might think that you’d need to override


clone( )

again to make sure


j

is copied, but that’s not the case. When


Int2

’s


clone( )

is called as


Int3

’s


clone( )

,


it calls


Object.clone( ),

which determines that it’s working with an


Int3

and duplicates all the bits in the


Int3

.


As long as you don’t add handles that need to be cloned, the one call to


Object.clone( )

performs all of the necessary duplication, regardless of how far down in the


hierarchy


clone( )

is defined.

You


can see what’s necessary in order to do a deep copy of a


Vector

:


after the


Vector

is cloned, you have to step through and clone each one of the objects pointed


to by the


Vector

.


You’d have to do something similar to this to do a deep copy of a


Hashtable

.

The


remainder of the example shows that the cloning did happen by showing that,


once an object is cloned, you can change it and the original object is left


untouched.


Deep
copy via serialization

When


you consider Java 1.1


object serialization (introduced in Chapter 10), you might observe that an
object that’s serialized and then deserialized is, in effect, cloned.

So


why not use

serialization
to perform deep copying? Here’s an example that compares the two
approaches by timing them:
//: Compete.java
import java.io.*;
 
class Thing1 implements Serializable {}
class Thing2 implements Serializable {
  Thing1 o1 = new Thing1();
}
 
class Thing3 implements Cloneable {
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println("Thing3 can't clone");
    }
    return o;
  }
}
 
class Thing4 implements Cloneable {
  Thing3 o3 = new Thing3();
  public Object clone() {
    Thing4 o = null;
    try {
      o = (Thing4)super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println("Thing4 can't clone");
    }
    // Clone the field, too:
    o.o3 = (Thing3)o3.clone();
    return o;
  }
}
 
public class Compete {
  static final int SIZE = 5000;
  public static void main(String[] args) {
    Thing2[] a = new Thing2[SIZE];
    for(int i = 0; i < a.length; i++)
      a[i] = new Thing2();
    Thing4[] b = new Thing4[SIZE];
    for(int i = 0; i < b.length; i++)
      b[i] = new Thing4();
    try {
      long t1 = System.currentTimeMillis();
      ByteArrayOutputStream buf =
        new ByteArrayOutputStream();
      ObjectOutputStream o =
        new ObjectOutputStream(buf);
      for(int i = 0; i < a.length; i++)
        o.writeObject(a[i]);
      // Now get copies:
      ObjectInputStream in =
        new ObjectInputStream(
          new ByteArrayInputStream(
            buf.toByteArray()));
      Thing2[] c = new Thing2[SIZE];
      for(int i = 0; i < c.length; i++)
        c[i] = (Thing2)in.readObject();
      long t2 = System.currentTimeMillis();
      System.out.println(
        "Duplication via serialization: " +
        (t2 - t1) + " Milliseconds");
      // Now try cloning:
      t1 = System.currentTimeMillis();
      Thing4[] d = new Thing4[SIZE];
      for(int i = 0; i < d.length; i++)
        d[i] = (Thing4)b[i].clone();
      t2 = System.currentTimeMillis();
      System.out.println(
        "Duplication via cloning: " +
        (t2 - t1) + " Milliseconds");
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
} ///:~ 
Thing2

and


Thing4

contain member objects so that there’s some deep copying going on.


It’s interesting to notice that while


Serializable

classes are easy to set up, there’s much more work going on to duplicate


them. Cloning involves a lot of work to set up the class, but the actual


duplication of objects is relatively simple. The results really tell the tale.


Here is the output from three different runs:

Duplication via serialization: 3400 Milliseconds
Duplication via cloning: 110 Milliseconds
 
Duplication via serialization: 3410 Milliseconds
Duplication via cloning: 110 Milliseconds
 
Duplication via serialization: 3520 Milliseconds
Duplication via cloning: 110 Milliseconds

Despite


the obviously huge time difference between serialization and cloning,


you’ll also notice that the serialization technique seems to vary


significantly in its duration, while cloning takes the same amount of time


every time.


Advertisement

Adding
cloneability

further
down a hierarchy

If


you create a new class, its base class defaults to


Object

,


which defaults to non-clonability (as you’ll see in the next section). As


long as you don’t explicitly add clonability, you won’t get it.

But
you can add it in at any layer and it will then be cloneable from that layer
downward, like this:
//: HorrorFlick.java
// You can insert Cloneability at any
// level of inheritance.
import java.util.*;
 
class Person {}
class Hero extends Person {}
class Scientist extends Person
    implements Cloneable {
  public Object clone() {
    try {
      return super.clone();
    } catch (CloneNotSupportedException e) {
      // this should never happen:
      // It's Cloneable already!
      throw new InternalError();
    }
  }
}
class MadScientist extends Scientist {}
 
public class HorrorFlick {
  public static void main(String[] args) {
    Person p = new Person();
    Hero h = new Hero();
    Scientist s = new Scientist();
    MadScientist m = new MadScientist();
 
    // p = (Person)p.clone(); // Compile error
    // h = (Hero)h.clone(); // Compile error
    s = (Scientist)s.clone();
    m = (MadScientist)m.clone();
  }
} ///:~ 

Before


clonability was added, the compiler stopped you from trying to clone things.


When clonability is added in


Scientist

,


then


Scientist

and all its descendants are cloneable.


Why
this strange design?

If


all this seems to be a strange scheme, that’s because it is. You might


wonder why it worked out this way. What is the meaning behind this design? What


follows is not a substantiated story – probably because much of the


marketing around Java makes it out to be a perfectly-designed language –


but it does go a long way toward explaining how things ended up the way they did.

Originally,


Java was designed as a language to control hardware boxes, and definitely not


with the Internet in mind. In a general-purpose language like this, it makes


sense that the programmer be able to clone any object. Thus,


clone( )

was placed in the root class


Object

,


but

it was a


public

method so you could always clone any object. This seemed to be the most


flexible approach, and after all, what could it hurt?

Well,


when Java was seen as the ultimate Internet programming language, things


changed. Suddenly, there are security issues, and of course, these issues are


dealt with using objects, and you don’t necessarily want anyone to be


able to clone your security objects. So what you’re seeing is a lot of


patches applied on the original simple and straightforward scheme:


clone( )

is now


protected

in


Object.

You must override it


and
implement
Cloneable

and

deal with the exceptions.

It’s


worth noting that you must use the


Cloneable

interface


only

if


you’re going to call


Object

’s


clone( )

,


method, since that method checks at run-time to make sure that your class


implements


Cloneable

.


But for consistency (and since


Cloneable

is empty anyway) you should implement it.



[49]

In C, which generally handles small bits of data, the default is pass-by-value.


C++ had to follow this form, but with objects pass-by-value isn’t usually


the most efficient way. In addition, coding classes to support pass-by-value in


C++ is a big headache.

[50]

This is not the dictionary spelling of the word, but it’s what is used in


the Java library, so I’ve used it here, too, in some hopes of reducing


confusion.

[51]

You can apparently create a simple counter-example to this statement, like this:

public
class Cloneit implements Cloneable {


public static void main (String[] args)


throws CloneNotSupportedException {


Cloneit a = new Cloneit();


Cloneit b = (Cloneit)a.clone();


}

}

However,
this only works because
main( )
is a method of
Cloneit
and thus has permission to call the
protected
base-class method
clone( ).
If you call it from a different class, it won’t compile.

Contents

|

Prev

|

Next
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.