object references

Started by
12 comments, last by Enigma 18 years, 3 months ago
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]
Advertisement
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?
Well I believe in God, and the only thing that scares me is Keyser Soze.
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
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 objectsassert g1 != g2;// gl.list and g2.list are seperate objectsassert g1.list != g2.list;// g1.list and g2.list both contain a reference to the same object, w1assert g1.list.get(0) == g2.list.get(0) && gl.list.get(0) == w1;System.out.println(g1.list.size()); // prints 1System.out.println(g2.list.size()); // prints 1g2.list.add(new Widget(2));System.out.println(g1.list.size()); // prints 1System.out.println(g2.list.size()); // prints 2System.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 objectsassert g1 != g2;// gl.list and g2.list are seperate objectsassert g1.list != g2.list;// g1.list and g2.list both contain a references to different objectsassert g1.list.get(0) != g2.list.get(0);System.out.println(g1.list.size()); // prints 1System.out.println(g2.list.size()); // prints 1g2.list.add(new Widget(2));System.out.println(g1.list.size()); // prints 1System.out.println(g2.list.size()); // prints 2System.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

This topic is closed to new replies.

Advertisement