http://www.developer.com/

Back to article

Object Integrity & Security: Duplicating Objects


May 2, 2007

Introduction

This series, The Object-Oriented Thought Process, is intended for someone just learning an object-oriented language and who wants to understand the basic concepts before jumping into the code, or someone who wants to understand the infrastructure behind an object-oriented language he or she is already using. These concepts are part of the foundation that any programmer will need to make the paradigm shift from procedural programming to object-oriented programming.

Click here to start at the beginning of the series.

In keeping with the code examples used in the previous articles, Java will be the language used to implement the concepts in code. One of the reasons that I like to use Java is because you can download the Java compiler for personal use at the Sun Microsystems Web site http://java.sun.com/. You can download the standard edition, J2SE 5.0, at http://java.sun.com/j2se/1.5.0/download.jsp to compile and execute these applications. I often reference the Java J2SE 5.0 API documentation and I recommend that you explore the Java API further. Code listings are provided for all examples in this article as well as figures and output (when appropriate). See the first article in this series for detailed descriptions for compiling and running all the code examples.

The code examples in this series are meant to be a hands-on experience. There are many code listings and figures of the output produced from these code examples. Please boot up your computer and run these exercises as you read through the text.

For the past several months, you have been exploring various issues regarding object integrity, security, and performance. In this month's article, you continue with this theme and begin to learn how objects are duplicated. This is not a trivial issue. Although copying primitives such as numbers is mostly straightforward, copying objects is a more complicated task.

Copying Objects

One of the interesting areas of object integrity pertains to the fact that developers often do not know what they have; in many cases, this can cause significant problems. Duplicating objects falls into this category. The problem is that objects are processed using pointers and references. Duplicating a pointer or a reference does not necessarily duplicate the entire object. The main issue here is that objects are often made up of other objects—and these relationships are critical to consider.

Referencing the Object

Start with a simple example. Suppose that you have two classes, the actual application (with main) called Duplicate.java and a standalone class called Dog.java. The only action that this Duplicate application initially performs is to create a Dog object and print out its name, which you assign in the constructor as 'fido'. Both classes are presented in Listing 01.

// Class Dog
class Dog {

   String name;
   String breed;

   public Dog(String n, String b) {

      name  = n;
      breed = b;

   }

   public String getName() {

      return name;

   }

   public String getBreed() {

      return breed;

   }

}

// Class Duplicate
public class Duplicate {

   public static void main(String[] args) {

   Dog fido = new Dog("fido", "retriever");

   System.out.println("name = " + fido.getName());

   }
}

Listing 01: The Duplicate Class

By looking at this graphically, you can see how the objects are represented in memory. Diagram 01 shows that the fido reference, defined by the circle, points to the physical memory location of the fido object. Internally, the details are a bit more complicated; however, the graphical representation provides a good way to understand what is happening, and it conveys the important concepts you are concerned about.

Diagram 01: An Object with a Single Reference.

The key to Figure 01 is to understand that when you access the fido object, you are really following a reference to the object. The address location of fido in the following line of code contains the address of the fido object. In many ways, this behavior is much easier to follow when using languages such as C/C++ that allow programmers to actually perform pointer arithmetic.

fido.getName();

In short, the 'fido' object in the line above is a reference, not the physical object.

When this application is executed, you get the output in Figure 01. It simply prints out the dog's name.

Figure 01: Simple Object Application

Although this application is very simple, you can quickly illustrate the issue you identified earlier in this article. Now, create a second Dog reference.

Dog spot;

There is no actual object created here. Note that there is no instantiation—you only create a reference here. To experienced developers, this may seem obvious; however, when teaching objects to students for the first time, this is a major area of confusion. No actual spot object has been created. However, you still can use the spot reference; you just need to understand what you can use it for.

For example, consider the following operation. You can actually assign the spot reference to the fido reference.

spot = fido;

Here is the important concept: Although you can assign these references to the same object, you are not copying anything. In this case, there is still only a single object despite the fact that you have two references, even though this might not be obvious. Take a look at Listing 02.

// Class Dog
class Dog {

   String name;
   String breed;

   public Dog(String n, String b) {

      name  = n;
      breed = b;

   }

   public String getName() {

      return name;

   }

   public String getBreed() {

      return breed;

   }

}

// Class Duplicate
public class Duplicate {

   public static void main(String[] args) {

   Dog fido = new Dog("fido", "retriever");

   Dog spot;

   spot = fido;

   System.out.println("name = " + fido.getName());
   System.out.println("name = " + spot.getName());


   }
}

Listing 02: The Duplicate Class with Two References

You have added code to the application to illustrate the concepts just explained. In Listing 02, you create the spot reference and then include a print statement to verify that both the fido and the spot reference point to the same object. When you run the updated application, you can see in Figure 02 that both the fido and the spot references print out the same name, in this case the original fido object.

Figure 02: Simple Object Application With Two References

You can see the graphical representation in Diagram 02. Both of the references are actually pointing to the fido object despite the fact that one of the reference is called spot.

Diagram 02: An Object with Two References.

One of the issues here is that, if you change the name for one of the references, you change them for both. Add some code to change the name of spot. Take a look at the additional lines of code below.

// Class Dog

...
   public void setName(String n) {

      name = n;

   }

....

// Class Duplicate

....

   spot.setName("rover");

....

When you run this code, you can see in Figure 03 that both of the object references are accessing this same object—whose name was changed to rover.

C:column34>"C:Program FilesJavajdk1.5.0_07binjava"
            -classpath . Duplicate
name = rover
name = rover
C:column34>

Cloning Objects

What do you have to do to actually duplicate an object and create a duplicate instance? You could create a second object by hand. In the code below, you create a reference called fido1 and one called fido2.

Dog fido1 = new Dog("fido", "retriever");
Dog fido2 = new Dog("fido", "retriever");

There may be many reasons why you would want to duplicate objects. You may want to do some sort of conversion where you need most of the original information. Or, you may want to create a new object for another Dog that will contain most, but not all, of the original information. The problem with this approach is that all of the updated information must be set by hand. For example, if you want to change the breed type, you would have to explicitly code that.

The object class in Java provides a method called clone() that performs the physical copy of an object. Taking a look at the Java documentation, you see what the definition for clone() looks like (remember that all Java objects inherit from the object class).

java.lang
Class Object

java.lang.Object

public class Object

Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.

Since:
JDK1.0

See Also:
Class
Method Summary
protected  Object clone()
Creates and returns a copy of this object.

>http://java.sun.com/j2se/1.5.0/docs/api/index.html

Using the clone() method does take a bit of work. In Listing 03, you add the line of code to clone the object (see the line in red).

// Class Duplicate
public class Duplicate {

   public static void main(String[] args) {

      Dog fido = new Dog("fido", "retriever");

      Dog spot;

      spot = fido.clone();

      System.out.println("name = " + fido.getName());
      System.out.println("name = " + spot.getName());


   }
}

Listing 03: The Duplicate Class

However, when you compile this code, you run into some tricky issues. As you can see in Figure 03, the coding involved is not totally straightforward. Specifically, you have two issues that you have to deal with. The first is the fact that the clone() method in the object class is defined as protected. The second comes into play because the compiler complains that the cloning procedure is dealing with incompatible types.

Figure 03: Attempting to Clone an Object

The first issue can be dealt with by overriding the clone() method in the Dog class itself. In fact, the clone() method is meant as a standard interface and not a complete solution to object duplication. Thus, like constructors, you probably want to create your own version of the clone() method.

In Listing 04, you add the code for the localized clone() method override in red. You will explore this code in much more detail in the next column; however, pay special attention to the fact that the Dog class implements the Clonable interface and that you must make provisions to catch the CloneNotSupportedException exception.

// Class Dog
class Dog implements Cloneable {

   String name;
   String breed;

   public Dog(String n, String b) {

      name  = n;
      breed = b;

   }

   public Object clone() {
      try {
         return super.clone();
      } catch (CloneNotSupportedException e) {
         throw new InternalError(e.toString());
      }
   }

   public String getName() {

      return name;

   }

   public void setName(String n) {

      name = n;

   }

   public String getBreed() {

      return breed;

   }

}

Listing 04: The Dog Class with the clone() Override

The second issue deals with casting. When the clone() method returns the object, the object in this case is of type Dog. Thus, you need to cast the return to the type Dog. This is illustrated in Listing 05.

// Class Duplicate
public class Duplicate {

   public static void main(String[] args) {

      Dog fido = new Dog("fido", "retriever");

      Dog spot;

      spot = (Dog) fido.clone();

      System.out.println("name = " + fido.getName());
      System.out.println("name = " + spot.getName());


   }
}

Listing 05: The Duplicate Class with the clone() method

With both of the changes in place, you can run the code that produces the output in Figure 4.



Click here for a larger image.

Figure 1.Cloning an Object

Now, this output looks identical to the output in Figure 02, without cloning the object—and this is in fact the case. The primary difference, and the important difference, is that there are now two totally separate objects. As you did with the previous two examples, you can represent this graphically to illustrate how the objects are represented in memory. Diagram 03 shows that in this case you not only have two references, you also have two objects.

Diagram 03: An Object with Two References to Two Objects.

When you look at Diagram 03, you may notice one inconsistency; the spot object still has the name defined as fido. In fact, the output in Figure 04 confirms this. This makes sense because you did clone the object, and this implies that all of the information is duplicated. Given this fact, how do you prove that the objects are indeed separate? Change the value of one, but not the other, as seen in Listing 06. Logically, you need to change the name of the spot object to "spot". You use the setName() method that you added earlier.

// Class Duplicate
public class Duplicate {

   public static void main(String[] args) {

      Dog fido = new Dog("fido", "retriever");

      Dog spot;

      spot = (Dog) fido.clone();

      spot.setName("Spot");

      System.out.println("name = " + fido.getName());
      System.out.println("name = " + spot.getName());


   }
}

Listing 06: Change the name for the spot reference

Figure 05: Cloning an Object

At this point, the graphical representation is in a logical state, the fido references and object with the name of fido, and the spot references and object with the name of spot, as seen in Diagram 04.

Diagram 04: An Object with Two References to Two Objects.

Conclusion

At this point, you have covered some of the basic mechanics of duplicating objects. As you can see, duplicating objects is not really as simple as it might seem. Copying primitives, such as a double, can be accomplished by a simple variable declaration and an assignment as seen below.

// Code to create a duplicate double data type

double a = 5;
double b = 0;

b = a;

This works because the double represents only a single address location (however many bytes that a double consumes). Because objects potentially contain other primitives and other objects, the number of address references is not limited to a single address reference. With objects, duplication is much more involved. You will explore more of these details in future articles.

This is where the concept of shallow and deep copies comes into play. You will take a look at these concepts as you continue to explore the cloning process.

References

About the Author

Matt Weisfeld is a faculty member at Cuyahoga Community College (Tri-C) in Cleveland, Ohio. Matt is a member of the Information Technology department, teaching programming languages such as C++, Java, C#, and .NET as well as various web technologies. Prior to joining Tri-C, Matt spent 20 years in the information technology industry, gaining experience in software development, project management, business development, corporate training, and part-time teaching. Matt holds an MS in computer science and an MBA in project management. Besides The Object-Oriented Thought Process, which is now in its second edition, Matt has published two other computer books, and more than a dozen articles in magazines and journals such as Dr. Dobb's Journal, The C/C++ Users Journal, Software Development Magazine, Java Report, and the international journal Project Management. Matt has presented at conferences throughout the United States and Canada.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date