Sign in to follow this  

object references

This topic is 4353 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am writing in Java and want to make sure I understand how object references work. Observe: class Widget { /* blah */ } Widget a = new Widget(); a.xyz = 15; a.hasSpinach = true; Widget b = a; Now if I change the properties of Widget 'b': b.xyz = 40; Does that mean I also changed the value of 'xyz' in Widget 'a'??

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
No. Objects are only by reference when used as a function argument.

Widget b = a; just creates a copy of a.

Share this post


Link to post
Share on other sites
I'll second rip-off's response, just to reinforce that his is the right response. The ONLY time an expression like "b = a" leads to a copy of a is if variables a and b are of a primitive type, which in Java are int, float, double, and boolean. The only way to copy an object is to use the clone method or to write your own method to create a copy of it.

Share this post


Link to post
Share on other sites
Quote:
Original post by hisDudeness
I am writing in Java and want to make sure I understand how object references work.

Observe:

class Widget { /* blah */ }

Widget a = new Widget();
a.xyz = 15;
a.hasSpinach = true;

Widget b = a;

Now if I change the properties of Widget 'b':

b.xyz = 40;

Does that mean I also changed the value of 'xyz' in Widget 'a'??


Yes.

Share this post


Link to post
Share on other sites
Quote:
Original post by hisDudeness
Widget a = new Widget();
a.xyz = 15;
Widget b = a;
b.xyz = 40;

Does that mean I also changed the value of 'xyz' in Widget 'a'??

Yes, because both a and b do not contain Widget-Objects but merely references to Widget-Objects.

Share this post


Link to post
Share on other sites
If you wanted to create a copy of a and store it in b you should implement an override of Object.clone - this method is inherited by all classes (since in Java every class is a superclass of java.lang.Object):

class Widget {
private int member_;

public Widget clone() {
Widget newWidget = new Widget( this.member_ );
return newWidget;
}

public Widget(int val) {
this.member_ = val; }

// ...etc..
}

Now you can use this function to "copy-construct" a new instance of Widget:

Widget a = new Widget(42); // creates a new widget
Widget b = a.clone(); // creates a new widget with same state as a
b.setMember(1337); // sets b's member (which was 42) to 1337.
// a's member is unchanged, because b != a.

Yay :D


EDIT: Yeah, I'm an idiot. Object.clone should have a return type of Object, not Widget -

public Object clone() { .. }

Sorry 'bout that :/

[Edited by - Mushu on January 10, 2006 6:23:49 PM]

Share this post


Link to post
Share on other sites
Okay so I'm looking to take Mushu's advice on cloning because I want to simplfy create exact copies of my objects, instead of creating two object references that manage the same object.

Mushu, using the source code you provided I got a compilation error:


class Widget
{
int member;

Widget(int val)
{
member = val;
}

Widget clone()
{
Widget w = new Widget(member);
return w;
}
}



javac is complaining that I cannot override Object's clone() method because access to it is protected. Now the only way my source code (above) differs from yours is that I chose not to make my Widget's 'member' member private. Perhaps this is the source of the error, but regardless, I do not want my Widget members to be private.

To patch the glitch, I just changed the name of the method to xclone() but used the same source code. However, it doesn't work! Observe:

Widget a = new Widget(5);
Widget b = a.xclone();
a.member = 20;

If I print Widget b's 'member' to screen, it stores the value as 20! The clone function has failed its purpose.


*pouting*

Share this post


Link to post
Share on other sites
Quote:
Original post by hisDudeness
\Now the only way my source code (above) differs from yours is that I chose not to make my Widget's 'member' member private.


You also didn't choose to make the clone() method public (the default is not the same thing as public). :)

Quote:
To patch the glitch, I just changed the name of the method to xclone() but used the same source code. However, it doesn't work! Observe:

Widget a = new Widget(5);
Widget b = a.xclone();
a.member = 20;

If I print Widget b's 'member' to screen, it stores the value as 20! The clone function has failed its purpose.


What you have should work. Make sure you recompiled properly.

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
i may be wrong, but doesnt clone return an Object?

Yeah, it does - I'm just an idiot and can't really get my brain around Java sometimes.

To expand upon the previous poster's reason as to why your code doesn't work (protected function compile error) is because clone is defined in Object as being protected (a scope which allows the containing class and all deriving classes access, and other classes in the same package). One of the 'rules' in Java is that you can't decrease the scope of a function/variable defined in a base class. By default, the scope of a function is what's called "package-level", which is between private and protected. So what the compiler's saying is that you're not allowed to decrease the visibility of Object.clone from protected to package-level.

The solution is, as the above poster mentioned, to define clone as public.

So the code (with these fixes) should look like this -

class Widget
{
int member;

public Widget(int val)
{
member = val;
}

public Object clone()
{
Widget w = new Widget(member);
return w;
}
}


Hopefully that answered some more questions - sorry about the earlier screw-up [wink]

Share this post


Link to post
Share on other sites
I think I've figured out what the problem is, but I can't seem to ponder a solution...

Widget is a base class for many other types, for example, Fidget and Gidget. A Fidget is a collection of primitive types, whereas a Gidget holds a LinkedList in addition to a few other primitives.

When I write the clone functions for Fidget and Gidget, I've noticed that the clone works properly on the Fidget, and fails on the Gidget. Observe:


class Widget
{
int foo;

public Widget(int x)
{
foo = x;
}
}

class Fidget extends Widget
{
int y;
int z;
boolean hasSpinach;

public Fidget(int a, int b, int c, boolean b)
{
x = a;
y = b;
z = c;
hasSpinach = b;
}

public Object clone()
{
Fidget f = new Fidget(x,y,z,hasSinach);
return f;
}
}

class Gidget extends Widget
{
char c;
LinkedList<Widget> list;

public Gidget(int a, char ch, LinkedList<Widget> l)
{
x = a;
c = ch;
list = l;
}

public Object clone()
{
Gidget g = new Gidget(x,c,list);
return g;
}
}



Say I make to Widget children, one of each type:

Fidget f = new Fidget(1,2,3,true);
LinkedList<Widget> tempList = new LinkedList<Widget>();
/* Populate the list here with Widgets, Fidgets, or Gidgets */
Gidget g = new Gidget(5,'s',tempList);

Now I want to test their clone methods:

Fidget fClone = (Fidget)f.clone();
Gidget gClone = (Gidget)g.clone();

Now I change the originals a leedle bit:

f.x = 538;
f.hasSpinach = false;

g.c = 'U';
g.list.add(new Widget(36));

When I print out a comparison list of all four objects' member values, I find that f and fClone are different (the clone() method worked), but g and gClone still have the same list value.

This must be because a LinkedList is an Object itself. And, in my clone() method, I simply pass the Object (by reference) into the newly-allocated clone Widget which gets returned. Hence, the same LinkedList object just keeps gets more and more object managers with every clone I make...but no new LinkedLists clones are made!

How can I circumvent this glitch?

Share this post


Link to post
Share on other sites

class Gidget extends Widget
{
char c;
LinkedList<Widget> list;

public Gidget(int a, char ch, LinkedList<Widget> l)
{
x = a;
c = ch;

// make a copy of the list, and a copy of all the widgets
list = new LinkedList();
ListIterator i = l.listIterator()
while( i.hasNext() )
{
list.add( i.next().clone() );
}
}

public Object clone()
{
Gidget g = new Gidget(x,c,list);
return g;
}
}



i havent used java in a bit, so i wouldnt expect it to compile, but that seems to be what you need to do

Share this post


Link to post
Share on other sites
It depends how deeply you want to clone. You could modify your Gidget clone method to:
public Object clone()
{
Gidget g = new Gidget(x,c,list.clone());
return g;
}

which would shallow copy your list, leaving:
Widget w1 = new Widget(1);
LinkedList< Widget > ll = new LinkedList< Widget >();
ll.add(w1);
Gidget g1 = new Gidget(1, 'a', ll);
Gidget g2 = g1.clone();

// g1 and g2 are seperate objects
assert g1 != g2;

// gl.list and g2.list are seperate objects
assert g1.list != g2.list;

// g1.list and g2.list both contain a reference to the same object, w1
assert g1.list.get(0) == g2.list.get(0) && gl.list.get(0) == w1;

System.out.println(g1.list.size()); // prints 1
System.out.println(g2.list.size()); // prints 1
g2.list.add(new Widget(2));
System.out.println(g1.list.size()); // prints 1
System.out.println(g2.list.size()); // prints 2

System.out.println(g1.list.get(0).foo); // prints '1';
System.out.println(g2.list.get(0).foo); // prints '1';
g2.list.get(0).foo = 3;
System.out.println(g1.list.get(0).foo); // prints '3';
System.out.println(g2.list.get(0).foo); // prints '3';

Or you could implement it as:
public Object clone()
{
LinkedList< Widget > newList = new LinkedList< Widget >();
ListIterator< Widget > iter = list.listIterator();
while (iter.hasNext())
{
newList.add(iter.next().clone());
}

Gidget g = new Gidget(x,c,newList);
return g;
}

Which, assuming that Widget.clone() always performs a deep-copy will perform a proper deep copy of the list, leaving:
Widget w1 = new Widget(1);
LinkedList< Widget > ll = new LinkedList< Widget >();
ll.add(w1);
Gidget g1 = new Gidget(1, 'a', ll);
Gidget g2 = g1.clone();

// g1 and g2 are seperate objects
assert g1 != g2;

// gl.list and g2.list are seperate objects
assert g1.list != g2.list;

// g1.list and g2.list both contain a references to different objects
assert g1.list.get(0) != g2.list.get(0);

System.out.println(g1.list.size()); // prints 1
System.out.println(g2.list.size()); // prints 1
g2.list.add(new Widget(2));
System.out.println(g1.list.size()); // prints 1
System.out.println(g2.list.size()); // prints 2

System.out.println(g1.list.get(0).foo); // prints '1';
System.out.println(g2.list.get(0).foo); // prints '1';
g2.list.get(0).foo = 3;
System.out.println(g1.list.get(0).foo); // prints '1';
System.out.println(g2.list.get(0).foo); // prints '3';

Obviously, the deeper you copy the more expensive copying becomes.

<disclaimer>none of the above code has been run through a compiler</disclaimer>

Enigma

Share this post


Link to post
Share on other sites

This topic is 4353 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this