Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Sep 18th, 2007, 4:58 PM   #1
cwl157
Professional Programmer
 
Join Date: Feb 2005
Posts: 345
Rep Power: 4 cwl157 is on a distinguished road
why does it change both instances

Alright, so i have a class that contains a 2d array. I make 2 instances of it with the same 2d array arrangement in both of them. If i change one of them the other changes as well for some reason. I can not figure out why both change. Shouldn't only the one instance change?
Here is the node class
import java.io.*;
public class GridNode
{
  private int[][] state;
  private GridNode firstChild;
  private GridNode nextSibling;
  
  // set state to newState and firstChild to newFirstChild and nextSibling to newNextSibling
   public GridNode(int[][] newState, GridNode newFirstChild, GridNode newNextSibling)
   {
      state = newState;
      firstChild = newFirstChild;
      nextSibling = newNextSibling;
   } // end GridNode constructor
 
   // get current state
   public int[][] getState()
   {
      return state;
   } // end getState
   
   public void setState(int[][] newState)
   {
      state = newState;
   } // end setState
   
   // set firstChild
   public void setFirstChild(GridNode newFirstChild)
   {
      firstChild = newFirstChild;
   } // end setFirstChild
   
   // set nextSibling
   public void setNextSibling(GridNode newNextSibling)
   {
       nextSibling = newNextSibling;
   } // end setNextSibling
   
   // get firstChild
   public GridNode getFirstChild()
   {
      return firstChild;
   } // end getFirstChild
   
   // get nextSibling
   public GridNode getNextSibling()
   {
      return nextSibling;
   } // end getNextSibling
   
   // print the current state
   public void printNode()
   {
      for(int row = 0; row < 3; row++)
      {
        for(int col = 0; col < 3; col++)
          System.out.print(state[row][col] + "   ");
        
        System.out.println();
      } // end for
    } // end printNode
   
   // check to see if current state is equal to the goal state
   public boolean isEqual(int[][] state, int[][] goalState)
   {
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
            if (state[row][col] == goalState[row][col])
               continue;
            
            else
             return false;
         } // end for
      }  // end for
      return true;
   } // end isEqual
   
   // calculates h1(n)
   public int findHone(int[][] state, int[][] goalState)
   {
      int hOne = 0;
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
            if (state[row][col] != goalState[row][col] && state[row][col] != 0)
               hOne++;
            
            else
             continue;
         } // end for
      }  // end for
      return hOne;
   } // end findHone
   
   // find f(n) = g(n) + h(n)
   public int findF(int g, int h)
   {
      return g + h;
   } // end findF
   
   // check to see if it can move left
   public boolean canMoveLeft(int[][] state)
   {
      int tempPos = -1;
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
             if (state[row][col] == 0)
                tempPos = col;
         } // end for
      } // end for
      
      if (tempPos == 0)
        return false;
      else
       return true;
   } // end canMoveLeft
   
   // check to see if it can move up
   public boolean canMoveUp(int[][] state)
   {
      int tempPos = -1;
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
             if (state[row][col] == 0)
                tempPos = row;
         } // end for
      } // end for
      
      if (tempPos == 0)
        return false;
      else
       return true;
   } // end canMoveUp
   
   // check to see if it can move right
   public boolean canMoveRight(int[][] state)
   {
      int tempPos = -1;
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
             if (state[row][col] == 0)
                tempPos = col;
         } // end for
      } // end for
      
      if (tempPos == 2)
        return false;
      else
       return true;
   } // end canMoveRight
   
   // check to see if it can move down
   public boolean canMoveDown(int[][] state)
   {
      int tempPos = -1;
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
             if (state[row][col] == 0)
                tempPos = row;
         } // end for
      } // end for
      
      if (tempPos == 2)
        return false;
      else
       return true;
   } // end canMoveDown
   
    // move it left, the old one
   public void moveLeft(int[][] state)
   {
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
             if (state[row][col] == 0)
             {
                  state[row][col] = state[row][col-1];
                  state[row][col-1] = 0;
                  //printNode();
                  return;
             } // end if
         } // end for
      } // end for
   } // end moveLeft
   
   
   // move it Up
   public void moveUp(int[][] state)
   {
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
             if (state[row][col] == 0)
             {
                  state[row][col] = state[row-1][col];
                  state[row-1][col] = 0;
                 // printNode(state);
                  return;
             } // end if
         } // end for
      } // end for
   } // end moveUp
   
    // move it right
   public void moveRight(int[][] state)
   {
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
             if (state[row][col] == 0)
             {
                   state[row][col] = state[row][col+1];
                   state[row][col+1] = 0;
                  // printNode(state);
                   return;
             } // end if
         } // end for
      } // end for
   } // end moveRight
   
    // move it down
   public void moveDown(int[][] state)
   {
      //int tempPos = -1;
      for (int row = 0; row < 3; row++)
      {
         for (int col = 0; col < 3; col++)
         {
             if (state[row][col] == 0)
             {
                 state[row][col] = state[row+1][col];
                 state[row+1][col] = 0;
                // printNode(state);
                 return;
             } // end if
         } // end for
      } // end for
   } // end moveDown
   
} // end GridNode

main where the 2 instances and everything is created
public class NewMain
{
   //insert new value, check to see if swap is needed
/* static void realInsert(GridNode parent, GridNode newNode)
  {
      if (parent.getFirstChild() == null)
	parent.setFirstChild(newNode);
      else
	realInsert(parent.getFirstChild().getNextSibling(), newNode);
      if(parent.canMoveLeft(parent.getState()))
      {
        parent.moveLeft(parent.getState());
        System.out.println("parent after move left:");
        parent.printNode();
        newNode.setState(parent.getState());
        System.out.println();
        System.out.println("newNode after setState is called");
        newNode.printNode();
        parent.moveRight(parent.getState());
        System.out.println();
        System.out.println("parent after move back happens");
        parent.printNode();
        System.out.println("one final print out of newNode");
        newNode.printNode();
      } // end if
  */    
 // } // end realInsert
   public static void main(String[] args)
   {
       int[][] initialState = {{7, 6, 4},
                             {8, 5, 2},
                             {1, 0, 3}
                            };
      GridNode parent = new GridNode(initialState, null, null);
      GridNode child = new GridNode(parent.getState(), null, null);
   
      parent.setFirstChild(child);
      
      child.moveLeft(child.getState());
      System.out.println("this is the child");
      child.printNode();
      
       System.out.println();
      System.out.println("This is the parent");
      parent.printNode();
      
      
       System.out.println();
      System.out.println("this is the initial state");
      for (int i = 0; i < 3; i++)
      {
          for (int j = 0; j < 3; j++)
          {
              System.out.print(initialState[i][j] + "    ");
          }
          System.out.println();
      }
      
      
   } // end main
 
} // end NewMain
cwl157 is offline   Reply With Quote
Old Sep 18th, 2007, 7:43 PM   #2
titaniumdecoy
Expert Programmer
 
titaniumdecoy's Avatar
 
Join Date: Nov 2005
Posts: 908
Rep Power: 3 titaniumdecoy is on a distinguished road
Send a message via AIM to titaniumdecoy
Object variables in Java are references (similar to pointers in C). If you need an independent copy of an object you need to make it; this is usually done by implementing the Cloneable interface and overriding the clone method to create and return a new copy of the object. You might also want to investigate the difference between a "shallow" copy and a "deep" copy.
titaniumdecoy is offline   Reply With Quote
Old Sep 18th, 2007, 7:52 PM   #3
cwl157
Professional Programmer
 
Join Date: Feb 2005
Posts: 345
Rep Power: 4 cwl157 is on a distinguished road
i thought that when a new instance of a class is created that a new copy of each of the methods and variables of that class went along with it. So you see the int[][] state. Lets say when i create a new GridNode, a new int[][] state is not created along with it? Then how do i do this? I do I make it so that when i say
GridNode n = new GridNode(initialState, null, null);

How do i make it so that it will create a new initialState, another copy of int[][] for the new node. I am going to be doing minor manipulations to each new instance so my goal was to just create a copy of the first instances int[][] into the other ones and then do the manipulations on the other ones. But if i can't just do that with out it taking the old one with it, then what do i do? I have never heard of clonable or anything. i've been stuck on this problem for over 2 days and just want to know what im doing wrong and make it work properly. Thanks.
cwl157 is offline   Reply With Quote
Old Sep 18th, 2007, 8:23 PM   #4
titaniumdecoy
Expert Programmer
 
titaniumdecoy's Avatar
 
Join Date: Nov 2005
Posts: 908
Rep Power: 3 titaniumdecoy is on a distinguished road
Send a message via AIM to titaniumdecoy
Now that I look more closely at your problem, I see that it is not object copying you are having trouble with but rather Java's strange implementation of arrays. Strangely enough, an array in Java is a actually a reference to an "array object" which holds references to its elements. So when you create a new GridNode as you do in the line of code you posted above, the variable n points to a distinct GridNode object. However, when you pass the initialState 2D array as an argument to the constructor, the state variable of the GridNode is a reference the original 2D array. The simplest solution is to simply call the array's clone method to create a new array. (Alternatively you could simply loop over each element and copy it into a new array; see this article for other methods.) The following example might help:

int[] p = { 1, 2, 3, 4 };
int[] q = p;

q[0] = 5;

System.out.println("p" + Arrays.toString(p) + ", q" + Arrays.toString(q));
// Output: p[5, 2, 3, 4], q[5, 2, 3, 4]

q = (int[])p.clone();

q[0] = 1;

System.out.println("p" + Arrays.toString(p) + ", q" + Arrays.toString(q));
// Output: p[5, 2, 3, 4], q[1, 2, 3, 4]

Last edited by titaniumdecoy; Sep 18th, 2007 at 8:40 PM.
titaniumdecoy is offline   Reply With Quote
Old Sep 18th, 2007, 8:47 PM   #5
cwl157
Professional Programmer
 
Join Date: Feb 2005
Posts: 345
Rep Power: 4 cwl157 is on a distinguished road
so i think i get what your saying but then how would i make that happen because i am going to be creating like 17 or so of these GridNodes, each with a different 2d array associated to it. Should i have a method in the GridNode class that does this and then call that whenever i create a new instance or something? I tried this just to see if i could get it to work and it didnt.
  
      GridNode parent = new GridNode(initialState, null, null);
      GridNode child = new GridNode(initialState, null, null);
      child.setState((int[][]) parent.getState().clone());

I also tried this and it didnt work either
 GridNode parent = new GridNode(initialState, null, null);
      GridNode child = new GridNode((int[][]) parent.getState().clone(), null, null);
cwl157 is offline   Reply With Quote
Old Sep 18th, 2007, 9:52 PM   #6
titaniumdecoy
Expert Programmer
 
titaniumdecoy's Avatar
 
Join Date: Nov 2005
Posts: 908
Rep Power: 3 titaniumdecoy is on a distinguished road
Send a message via AIM to titaniumdecoy
Okay, you have another (big) problem: When you name a parameter of a method the same as an instance variable of that class, the parameter variable "hides" the instance variable. So, in this snippet of code, for example:

public class GridNode
{
    private int[][] state;
    
    ...
    
    public void moveRight(int[][] state) {
        for (int row = 0; row < 3; row++) {
            for (int col = 0; col < 3; col++) {
                if (state[row][col] == 0) {
                    state[row][col] = state[row][col+1];
                    state[row][col+1] = 0;
                    return;
                }
            }
        }
    }
    
    ...
    
}
The state parameter, not the state instance variable, is being changed! As you can image, all sorts of problems will arise. (The original array, presumably declared in NewMain, will be altered, for the reasons described in my last post.) The solution: Either don't name any of your parameters the same as any of your instance variables or use the this keyword to qualify variables:

this.state[row][col] = state[row][col+1];
All that said, however, this is not the cause of your problem--and perhaps you intended that behavior. If so, the method should be declared static (and you might want to consider changing the parameter name anyway for obvious reasons).

Last edited by titaniumdecoy; Sep 18th, 2007 at 10:11 PM.
titaniumdecoy is offline   Reply With Quote
Old Sep 18th, 2007, 10:05 PM   #7
titaniumdecoy
Expert Programmer
 
titaniumdecoy's Avatar
 
Join Date: Nov 2005
Posts: 908
Rep Power: 3 titaniumdecoy is on a distinguished road
Send a message via AIM to titaniumdecoy
The cause of your problem is the fact that the clone method of a 2D array creates a shallow copy. (Stupid? Yes.) Think of a 2D array as an object with X references to Y 1D arrays (each of which contain additional references--the actual objects stored in the array). The clone method of a 2D array creates a new 2D array--but copies the references to the 1D arrays rather than cloning them! You can avoid this by writing your own method to copy a 2D array:

public static int[][] copy(int[][] a) {
    int[][] b = new int[a[0].length][a.length];
    for (int i = 0; i < a.length; i++)
        for (int j = 0; j < a[0].length; j++)
            b[i][j] = a[i][j];
    return b;
}
Hopefully that will solve your problem.
titaniumdecoy is offline   Reply With Quote
Old Sep 18th, 2007, 10:11 PM   #8
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
Titanium is giving you the scoop, but you don't seem to get it. Let me make an analogy. Suppose you post a memo on the bulletin board, very top left corner. Someone asks you what the memo says. You refer them to the upper left corner. Someone else asks you what the memo says. You refer them to the upper left corner.

If someone else comes along and scratches out part of the memo and replaces it, all referrals to the upper left corner memo look the same. The ARE the same.

That's a reference. If you give someone a note that says, "Upper left corner", and someone else a note that says, "Upper left corner", that's two different notes, but the reference is the same, The second note is a shallow copy of the first.

On the other hand, if you copy the memo and hand that out, instead of a reference to the bulletin board, that's a deep copy. If only Joe's is changed, Fred doesn't see that.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Sep 18th, 2007, 10:42 PM   #9
cwl157
Professional Programmer
 
Join Date: Feb 2005
Posts: 345
Rep Power: 4 cwl157 is on a distinguished road
alright so now if i wanted to make a tree with one child and then the child having up to 3 siblings all consisting of GridNodes but each int[][] state of the GridNodes would be different, how would i do that. I get the firstChild points to the child and then the nextSibling would point to the sibling and then i set those to null when i first create the instance and then when needed set them but i need to keep track of what level of the tree im in and all that too. I'm just really lost when it comes to trees so i took a class that deals with them hoping to learn only to find out today that the teacher doesn't help anyone so im actually kinda lost right now.

Alright so this is what i got on how to get it to work like i want it to
 int[][] initialState = {{7, 6, 4},
                             {8, 5, 2},
                             {1, 0, 3}
                            };
      
       //int[][] childState = parent.copy(parent.getState());
      GridNode parent = new GridNode(initialState, null, null);
      int[][] childState = parent.copy(parent.getState());
       GridNode child = new GridNode(childState, null, null);

but now i ask if im gonna be creating a bunch of children, is there a way for me to do it without having to create a new corresponding int[][] along with it? Because then to refer to it instead of saying child.getState() to get the state couldnt i just not even use the class and just create a new int [][] within this class and just refer to that for everything?
cwl157 is offline   Reply With Quote
Old Sep 18th, 2007, 11:20 PM   #10
cwl157
Professional Programmer
 
Join Date: Feb 2005
Posts: 345
Rep Power: 4 cwl157 is on a distinguished road
i think i got it. This is what the if statement looks like for making the left child of the tree

if (parent.canMoveLeft(parent.getState()))
     {
         child.setState(parent.copy(parent.getState()));
         child.moveLeft(child.getState());
         parent.setFirstChild(child);
         System.out.println(parent.getFirstChild());
         child.printNode();
         System.out.println();
         parent.printNode();
     } // end if
cwl157 is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Change Link Order matthewvb PHP 1 Dec 20th, 2006 1:13 AM
How To Change The Style/Class Of An Object? Sane JavaScript and Client-Side Browser Scripting 16 May 26th, 2006 11:15 AM
Cant Change Font Properties, Urgent brokenhope Visual Basic .NET 11 Sep 20th, 2005 4:42 PM
how to change text colour in C chungchung C 6 Aug 16th, 2005 4:00 PM
How can I change .asp page of frame after every 5-10 minutes ? sham ASP 1 May 1st, 2005 9:25 PM




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 5:08 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC