Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 3 of 3

Thread: Using serializable yet still getting a shallow copy of object

  1. #1
    Junior Member
    Join Date
    Oct 2012
    Posts
    8
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default Using serializable yet still getting a shallow copy of object

    I have browsed the other questions and found solutions as to how to do a deep copy of objects that contain references. I am specifically wanting to make a deep copy of a tree. Logically, each tree node contain references to its children nodes. Here is the basics of my node class
    public class BSTNode implements Comparable, Serializable  {
     
        private String token;
        private int count;
        private BSTNode leftChild;
        private BSTNode rightChild;

    I know I must only be making a shallow copy because when I make a copy of tree1, called tree2, and edit tree1 the edits also appear on tree2. Here is my copy method within my BSTNode class
    public  BSTNode copy()
       {
       BSTNode obj = null;
       try{
           ByteArrayOutputStream bos = new ByteArrayOutputStream();
           ObjectOutputStream out = new ObjectOutputStream(bos);
           out.writeObject(this);
           out.flush();
           out.close();
     
           ObjectInputStream in= new ObjectInputStream(new ByteArrayInputStream(
                   bos.toByteArray()));
           obj = (BSTNode) in.readObject();
       }
       catch(Exception e)
       {
           e.printStackTrace();
       }
       return obj;
     }
    When I wish to copy the entire tree, I call that above copy method from my BSTree class using the methods below. (I have 2 methods because this is a homework assignment that requires a copy method that calls a preorder traversal method)

     public BSTNode copy()
    {
        BSTNode copiedTreeRoot = new BSTNode();
        return copyTree(copiedTreeRoot,root);
    }
     
    public BSTNode copyTree(BSTNode copiedTreeRoot, BSTNode otherTreeRoot)
    {
        if(otherTreeRoot == null)
        {
            copiedTreeRoot = null;
        }
        else
        {
             copiedTreeRoot = otherTreeRoot.copy();
             copyTree(copiedTreeRoot.getLeft(), otherTreeRoot.getLeft());
            copyTree(copiedTreeRoot.getRight(), otherTreeRoot.getRight());          
        }
        return copiedTreeRoot;
    }
    I use these lines to create the new tree and assign the copy to it

    BSTree tree2 = new BSTree();
    tree2.setRoot(tree1.copy());

    And further along when I make changes to tree1, tree 2 also changes. I have no clue what I'm doing wrong. I believe it must be somewhere in how I return the new tree or something. Any help is greatly appreciated!!

    --- Update ---

    I tried this edit to my copy method, but it made no difference.
      public  BSTNode copy()
       {
           BSTNode obj = null;
           try{
               ByteArrayOutputStream bos = new ByteArrayOutputStream();
               ObjectOutputStream out = new ObjectOutputStream(bos);
               out.writeObject(this);
               out.flush();
               out.close();
     
               ObjectInputStream in= new ObjectInputStream(new ByteArrayInputStream(
                       bos.toByteArray()));
               obj = (BSTNode) in.readObject();
           }
           catch(Exception e)
           {
               e.printStackTrace();
           }
          if(leftChild != null)
          {
             obj.setLeft(leftChild.copy());
          }
          if(rightChild != null)
          {  
           obj.setRight(rightChild.copy());
          }
           return obj;
       }


  2. #2
    Forum VIP
    Join Date
    Jul 2010
    Posts
    1,676
    Thanks
    25
    Thanked 329 Times in 305 Posts

    Default Re: Using serializable yet still getting a shallow copy of object

    I feel you tried to do recursion, but didn't use it to its full potential. I think I was able to create a method which transversed the tree and created its subtrees in only 8 lines of code, but if I just give it to you, you miss out on learning how to do it.

    So, instead I'll walk you through it. You seem to understand, in theory, your primary goals, but here they are anyway:
    1. create a new node
    2. copy the token and count values from the old node into the new node
    3. transverse the left child tree
    4. transverse the right child tree
    5. return the new node

    A quick review on the basic principles of recursion:
    For recursion like this, we usually have two methods:
    1. The first method will begin the recursion
    2. The second method is the one which does the recursing

    Also for recursion, we need two situations:
    1. An "end-case" which is reachable 100% of the time. This is basically just an indicator for when we have reached the end of our recursion stack.
    2. A recursive call.

    In your code blocks above, you attempted to tackle the recursion with your methods:
    1. public BSTNode copy() {...}
    2. public BSTNode copyTree(BSTNode copiedTreeRoot, BSTNode otherTreeRoot) {...}

    But, you made a common mistake in the copyTree() method: you tried to do too much. Recursion is really powerful because it implicitly handles a bunch of stuff you don't have to explicitly handle, so it can be confusing to get right some times.
    Your logic was clearly:
    1. send the node to copy as well as the node to add the subtrees to
    2. copy the data across
    3. copy the left tree
    4. copy the right tree
    While correct in principle, it is not correct in practice. A lot of the power from recursion comes from correct use of the value returned from the recursive method. In your code, you are not using that returned value in the recursive iterations. That is your mistake. Ideally, your copyTree() method would only take in one parameter. This parameter would be the node you want to copy. The value returned would be the fully copied node.
    Look at your copyTree() method. Where are you actually setting the left and right subtrees? The answer: you aren't.

    Now let's look at your updated code segment. In this code, you are setting the left and right subtrees with these lines of code:
    obj.setLeft(leftChild.copy());
    obj.setRight(rightChild.copy());
    All of the pieces are here for a recursive call, but you haven't utilized them correctly.

    Now, let's look at an outline for what a correct copyTree() method would look like:
    public BSTNode copyTree(BSTNode toCopy) {
    	// check if toCopy is null, and return null if it is
     
    	// create a new node, and copy the token and count values from toCopy to your new node
     
    	// recursively copy toCopy's left tree and set it as your new node's left tree
     
    	// recursively copy toCopy's right tree and set it as your new node's right tree
     
    	// return the newly created node
    }
    Each comment indicates a step for your method. I am going to let you try to figure out the code for each step. If you need any help, or anything I've said clarified, feel free to ask.
    NOTE TO NEW PEOPLE LOOKING FOR HELP ON FORUM:

    When asking for help, please follow these guidelines to receive better and more prompt help:
    1. Put your code in Java Tags. To do this, put [highlight=java] before your code and [/highlight] after your code.
    2. Give full details of errors and provide us with as much information about the situation as possible.
    3. Give us an example of what the output should look like when done correctly.

    Join the Airline Management Simulation Game to manage your own airline against other users in a virtual recreation of the United States Airline Industry. For more details, visit: http://airlinegame.orgfree.com/

  3. #3
    Administrator copeg's Avatar
    Join Date
    Oct 2009
    Location
    US
    Posts
    5,320
    Thanks
    181
    Thanked 833 Times in 772 Posts
    Blog Entries
    5

    Default Re: Using serializable yet still getting a shallow copy of object

    I'd recommend posting an SSCCE that reproduces the behavior you observe, because the following:
    import java.io.*;
     
    public class BSTNode implements Serializable  {
     
    	//static final long serialVersionUID = 432142L;
     
        private String token;
        private int count;
        private BSTNode leftChild;
        private BSTNode rightChild;
     
        public  BSTNode copy(){
        	BSTNode obj = null;
        	try{
        		ByteArrayOutputStream bos = new ByteArrayOutputStream();
        		ObjectOutputStream out = new ObjectOutputStream(bos);
        		out.writeObject(this);
        		out.flush();
        		out.close();
     
        		ObjectInputStream in= new ObjectInputStream(new ByteArrayInputStream(
        				bos.toByteArray()));
        		obj = (BSTNode) in.readObject();
        	}
        	catch(Exception e){
        		e.printStackTrace();
        	}
        	return obj;
        }
     
        public static void main(String[] args){
        	BSTNode root1 = new BSTNode();
        	System.out.println("--First Tree Values:");
        	root1.token = "Root1";
        	root1.leftChild = new BSTNode();
        	root1.rightChild = new BSTNode();
        	root1.leftChild.token = "Left";
        	root1.rightChild.token = "Right";
        	System.out.println(root1.token);
        	System.out.println(root1.leftChild.token);
        	System.out.println(root1.rightChild.token);
        	BSTNode root2 = root1.copy();
        	root2.token = "Root2";
        	root2.leftChild.token = "Right";
        	root2.rightChild.token = "Left";
        	System.out.println("--First Tree Values after Copy/Change:");
        	System.out.println(root1.token);
        	System.out.println(root1.leftChild.token);
        	System.out.println(root1.rightChild.token);
        	System.out.println("--Second Tree Values after Copy/Change:");
        	System.out.println(root2.token);
        	System.out.println(root2.leftChild.token);
        	System.out.println(root2.rightChild.token);
        }
    }
    Prints out the expected:
    --First Tree Values:
    Root1
    Left
    Right
    --First Tree Values after Copy/Change:
    Root1
    Left
    Right
    --Second Tree Values after Copy/Change:
    Root2
    Right
    Left

Similar Threads

  1. Replies: 0
    Last Post: February 21st, 2014, 09:48 PM
  2. Serializable arraylist as txt?
    By klskl in forum File I/O & Other I/O Streams
    Replies: 8
    Last Post: November 11th, 2013, 01:10 PM
  3. 2D array shallow and deep cloning
    By adrianvas12 in forum Object Oriented Programming
    Replies: 6
    Last Post: October 14th, 2013, 03:14 AM
  4. Stack implementation and shallow copy
    By Shaybay92 in forum Algorithms & Recursion
    Replies: 2
    Last Post: March 20th, 2012, 12:32 AM