Java Forum / General / July 2007
Backing Up Objects
Hal Vaughan - 09 Jul 2007 06:38 GMT This seems to me to be an issue in dealing with pointers and cloning objects. I understand that if I have two Objects, whether they're something like a String or an object I define myself, then when I do:
String newString = oldString;
that newString is simply a pointer to oldString so if I change the value in one, I change the value in the other.
What I'd like to do is copy an object I've created that has a few HashMaps in it to an entirely new object and make sure they are both separate. Whenever the data in this program is saved, a backup copy of this object would be created. That way, while I'm editing data in the program, if I make a mistake, I can easily restore things to the last time I saved by copying the back up object to the new object.
This object is essentially a data table and I have several of them, stored in a Vector. I've read that if I use clone() on a Vector, that a new Vector is created, but the new one will still point to all the same objects in the first Vector. If I iterate through the Vector and clone each Object in it and store each cloned object in a new Vector, will that new Vector have a copy of equivalent values without them being the same objects?
If that doesn't work, how can I create a backup of an Object so I can change the values in one while the values in the other stay the same?
Thanks!
Hal
Stefan Ram - 09 Jul 2007 11:11 GMT >String newString = oldString; If this is compilable, then »oldString« is the a name of a variable that contains a reference value. When this is executed, the other variable (named »newString«) will contain a copy of this reference value. But no object will be altered in the course of this action.
>how can I create a backup of an Object This depends on the circumstances. There are »shallow« copies only copying the fields and »deep« copies, where the fields are altered to refer to copies of subobjects (recursively), and there are mixtures. Only you can know, what is appropriate for your requirements. By this knowledge, you can implement the operation as a method.
Means to copy often are a »copy constructor« or the method »clone«. You might look up these subjects in the technical literature.
Lew - 09 Jul 2007 13:25 GMT Hal Vaughan writes:
> String newString = oldString; > > that newString is simply a pointer to oldString so if I change the value in > one, I change the value in the other. Ironically, under most circumstances it is not possible to change the value of a String, so this made a bad example. Strings are "immutable"; without resorting to evil reflection trickery their value cannot be changed after construction. An example using "Foo" instead of "String" would be valid (one would assume Foo is not immutable). However, the main point of the post is valid, that assignment copies references, not objects.
>> how can I create a backup of an Object
> This depends on the circumstances. There are »shallow« copies > only copying the fields and »deep« copies, where the fields [quoted text clipped - 5 lines] > Means to copy often are a »copy constructor« or the method »clone«. > You might look up these subjects in the technical literature. Hal Vaughan writes:
>> This object is essentially a data table and I have several of them, stored >> in a Vector. I've read that if I use clone() on a Vector, that a new Why did you use the senescent Vector class in lieu of, say, ArrayList or any other List (or more generic Collection) class? Vector is, what, seven or eight years out of date, and dangerous? If you need synchronized methods, Collections.synchronizedList( yourList ) is much safer than Vector.
 Signature Lew
Piotr Kobzda - 09 Jul 2007 21:31 GMT > Hal Vaughan writes: >> String newString = oldString; [quoted text clipped - 8 lines] > changed after construction. An example using "Foo" instead of "String" > would be valid (one would assume Foo is not immutable). One would assume "String" is immutable:
public class String { public java.lang.String value; public String toString() { return value; } }
piotr
Piotr Kobzda - 09 Jul 2007 21:35 GMT > Hal Vaughan writes: >> String newString = oldString; [quoted text clipped - 8 lines] > changed after construction. An example using "Foo" instead of "String" > would be valid (one would assume Foo is not immutable). One would assume "String" is mutable:
public class String { public java.lang.String value; public java.lang.String toString() { return value; } }
piotr
Lew - 10 Jul 2007 00:53 GMT Hal Vaughan writes:
>>> String newString = oldString; >>> >>> that newString is simply a pointer to oldString so if I change the >>> value in >>> one, I change the value in the other. Lew wrote:
>> Ironically, under most circumstances it is not possible to change the >> value of a String, so this made a bad example. Strings are >> "immutable"; without resorting to evil reflection trickery their value >> cannot be changed after construction. An example using "Foo" instead >> of "String" would be valid (one would assume Foo is not immutable).
> One would assume "String" is mutable: > > public class String { > public java.lang.String value; > public java.lang.String toString() { return value; } > } You're just being argumentative.
Absent any specific disclaimer to the contrary, as the original post was, why in the world would one figure that "String" meant anything other than "java.lang.String"? If you wish to assume the OP is an idiot who reuses the most fundamental class names, thus damaging maintenance, then perhaps, and only perhaps, your point would have a micro-skootch of merit, but I refuse to believe the OP was that stupid.
Be real.
 Signature Lew
Hal Vaughan - 10 Jul 2007 02:03 GMT > Hal Vaughan writes: >>>> String newString = oldString; [quoted text clipped - 27 lines] > > Be real. I may be self taught and, because of that, have missed quite a few of the basics (like the issue about others lists being better than vectors), but I can assure you the OP is NOT that stupid.
Dense and stubborn, maybe, but not that stupid.
Hal (The O.P.)
Piotr Kobzda - 10 Jul 2007 09:29 GMT > Hal Vaughan writes: >>>> String newString = oldString; [quoted text clipped - 19 lines] > > You're just being argumentative. No, I'm not. My apologies to all of you who have interpreted my post that way. That was just to show that there is other possibility (other than reflection mentioned by you) to mutate "String" value, which gives the above example similar sense as using Foo does. That's all.
> Absent any specific disclaimer to the contrary, as the original post > was, why in the world would one figure that "String" meant anything > other than "java.lang.String"? If you wish to assume the OP is an idiot > who reuses the most fundamental class names, thus damaging maintenance, > then perhaps, and only perhaps, your point would have a micro-skootch of > merit, but I refuse to believe the OP was that stupid. I have never assumed that. If the OP thinks I did, my apologies to him, that was not my intent.
> Be real. Well, I'll try. Thank you for advice.
piotr
Twisted - 10 Jul 2007 12:07 GMT > No, I'm not. My apologies to all of you who have interpreted my post > that way. That was just to show that there is other possibility (other > than reflection mentioned by you) to mutate "String" value, which gives > the above example similar sense as using Foo does. That's all. Of course, it doesn't *really* mutate a "String" value, in that your String is seen by the compiler as a different type to, and not assignable to, java.lang.String.
On the other hand, there is another real way to mutate a String -- alter it when it's serialized, then deserialize it.
Piotr Kobzda - 10 Jul 2007 13:25 GMT > Of course, it doesn't *really* mutate a "String" value, in that your > String is seen by the compiler as a different type to, and not > assignable to, java.lang.String. Of course, my String is different type. It simply allows to implement the scenario described by the OP:
<sscce> public class Test { public static void m(String[] args) { class String { java.lang.String value; public java.lang.String toString() { return value; } } String oldString = new String(); String newString = oldString; // the OP's line (literally) oldString.value = "123"; System.out.println(newString); } } </sscce>
> On the other hand, there is another real way to mutate a String -- > alter it when it's serialized, then deserialize it. That way you cannot mutate the value of an existing String object. It allows to create a new one only. To achieve similar effect, much easier is to use a String's "copy constructor".
piotr
Roedy Green - 09 Jul 2007 20:13 GMT On Mon, 09 Jul 2007 01:38:13 -0400, Hal Vaughan <hal@thresholddigital.com> wrote, quoted or indirectly quoted someone who said :
>String newString = oldString; > >that newString is simply a pointer to oldString so if I change the value in >one, I change the value in the other. No. All you can do is make newString point to a different string. OldString and all the references pointing to it are the same.
What you are describing is a char[].
If you change it, it changes for all references pointing to it. -- Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Twisted - 10 Jul 2007 04:38 GMT OK, it's high time *someone* answered the OP's question here.
If you want to do a full deep copy of a data structure, just serialize and deserialize it. If you want to, to a RAM buffer rather than a (possibly temporary) disk file. (The TCP/IP loopback interface is another intriguing possibility.) As an added bonus feature, if you serialize to a .bak file on disk you get a disk backup that can be restored later by deserializing it, e.g. after a program abend.
You need to make the stuff you use in this data structure serializable. The standard collection classes already are serializable. The Java Tutorial on Sun's Web site has further information about serialization for beginners.
Hal Vaughan - 10 Jul 2007 06:34 GMT > OK, it's high time *someone* answered the OP's question here. > [quoted text clipped - 9 lines] > serializable. The Java Tutorial on Sun's Web site has further > information about serialization for beginners. Thank you!
Now I have some good terms to use for searching. I can work it out from there.
Hal
Lew - 10 Jul 2007 12:28 GMT >> OK, it's high time *someone* answered the OP's question here. >> [quoted text clipped - 14 lines] > Now I have some good terms to use for searching. I can work it out from > there. You will probably find Stefan's advice (the very first answer to your post) more manageable. Serialization is a topic fraught with perils.
Stefan Ram suggested:
> This depends on the circumstances. There are »shallow« copies > only copying the fields and »deep« copies, where the fields [quoted text clipped - 5 lines] > Means to copy often are a »copy constructor« or the method »clone«. > You might look up these subjects in the technical literature. The usual best is to write your own copy method(s).
Serialization requires a number of steps to ensure safety, covered well by Joshua Bloch's /Effective Java/. You need a serialVersionUID, possibly to write methods writeObject(), readObject(), readObjectNoData(), writeReplace() and readResolve(), making certain fields transient, making sure all referenced objects are also serializable, more threading concerns, possible static variable trouble, and so on. It creates a back-door constructor and a public access to the class that must be maintained in perpetuity.
Just writing a copy method is likely to be much easier.
 Signature Lew
Hal Vaughan - 10 Jul 2007 17:21 GMT >>> OK, it's high time *someone* answered the OP's question here. >>> [quoted text clipped - 18 lines] > post) > more manageable. Serialization is a topic fraught with perils. I think I got confused at one point. I was listening to advice from a friend who seemed skeptical of that. Thanks for pointing that out. (And I'll point it out to my friend!)
> Stefan Ram suggested: >> This depends on the circumstances. There are »shallow« copies [quoted text clipped - 17 lines] > variable trouble, and so on. It creates a back-door constructor and a > public access to the class that must be maintained in perpetuity. Perpetuity is one thing I'm not concerned about. All I'm doing is storing, in RAM, a copy of what I've been working with until I either save it again (in which case I need a new copy for backup) or until I exit the program.
> Just writing a copy method is likely to be much easier. But if I'm writing a copy method, I have to write something that will take each Object I have in my class and duplicate it, which leads back to the original problem: How do I make an actual copy of an object? Are there types of Objects where clone() does an actual clone and create a new Object?
Thanks!
Hal
Twisted - 10 Jul 2007 20:33 GMT > But if I'm writing a copy method, I have to write something that will take > each Object I have in my class and duplicate it, which leads back to the > original problem: How do I make an actual copy of an object? Are there > types of Objects where clone() does an actual clone and create a new > Object? If you're just copying, say, an ArrayList of Foos where Foos are some simple value objects that implement Cloneable, you can use a custom copying method to do it easily.
If you've got a substantially more complex data structure which would have a nontrivial traversal algorithm and contains an open-ended variety of things, you're probably going to have a much easier time using serialization. That takes the matter of writing the traversal algorithm and getting it right out of your hands and leaves you without much more to do for most of your classes than Cloneable. With Cloneable you need to tack on "implements Cloneable" and include
public Object clone () { super.clone(); }
to make "clone" public, at minimum. And you've still introduced a "backdoor constructor" of sorts.
Serializability in a lot of cases just means tacking on "implements java.io.Serializable" and including private static final long serialVersionUID = 1;
and increasing this by one every time you make certain changes to the class in question (basically any change where there was a non- transient field with a particular name and there no longer is or a field changes type other than to a supertype of the old type, and any change where a non-transient field starts existing and cannot be null, false, or zero by default). More complex stuff is only infrequently needed, e.g. a singleton should have every field transient and a readResolve method that returns the singleton instance from a static field if for some reason it's serializable. (A singleton value object such as a Null or a NaN or an Infinity, for example, which is a subclass of some more general value type class.)
Hal Vaughan - 12 Jul 2007 10:40 GMT >> But if I'm writing a copy method, I have to write something that will >> take each Object I have in my class and duplicate it, which leads back to [quoted text clipped - 6 lines] > simple value objects that implement Cloneable, you can use a custom > copying method to do it easily. In the long run, the data comes down to Strings. While I have my own class that stores them, the bottom line is I'm storing Strings that I need to copy.
> If you've got a substantially more complex data structure which would > have a nontrivial traversal algorithm and contains an open-ended [quoted text clipped - 3 lines] > without much more to do for most of your classes than Cloneable. With > Cloneable you need to tack on "implements Cloneable" and include So if it's at all complex, I'm better using serialization? If so, there's one aspect to this I'm not sure of. I don't want to write the objects to anything. I'm only storing them within the program temporarily, either until the next save or until the program ends. From what I saw, using serialization means writing the data to a stream. Can that stream go to an object and be read back from that object later? (Instead of a stream being written to a file on the drive or through a network connection?)
> public Object clone () { > super.clone(); [quoted text clipped - 18 lines] > such as a Null or a NaN or an Infinity, for example, which is a > subclass of some more general value type class.) I'm not worried about changes, since any data written from one of my serializable objects would only be stored in RAM and never on disk. The longest it would last would be until the program exits, so version tracking is moot (unless I've missed something important).
Thanks!
Hal
Lew - 12 Jul 2007 15:14 GMT > So if it's at all complex, I'm better using serialization? If so, there's > one aspect to this I'm not sure of. I don't want to write the objects to [quoted text clipped - 3 lines] > object and be read back from that object later? (Instead of a stream being > written to a file on the drive or through a network connection?) <http://java.sun.com/javase/6/docs/api/java/io/ByteArrayOutputStream.html> <http://java.sun.com/javase/6/docs/api/java/io/ByteArrayInputStream.html>
I still prefer copy methods to serialization.
 Signature Lew
Hal Vaughan - 12 Jul 2007 15:36 GMT >> So if it's at all complex, I'm better using serialization? If so, >> there's [quoted text clipped - 10 lines] > > I still prefer copy methods to serialization. Okay, so how do I make copy of a String so I can modify either the copy or the original without effecting the other? (Yes, I know Strings follow different rules than other Objects, but this is a start.)
I'm not ruling copying out. I am still finishing up some other stuff and this is a few steps off for me. I've learned to look ahead and ask questions like this before I get to that part of my work so I have time to get answers and explore what people tell me about.
Hal
Lew - 12 Jul 2007 23:57 GMT > Okay, so how do I make copy of a String so I can modify either the copy or > the original without effecting [sic] the other? (Yes, I know Strings follow > different rules than other Objects, but this is a start.) As was pointed out a few times in this thread, you cannot modify a String's value.
Neither the copy nor the original.
You can copy a String a couple of ways, e.g., String original = "Something"; String copy = new String( original );
 Signature Lew
Hal Vaughan - 13 Jul 2007 03:04 GMT >> Okay, so how do I make copy of a String so I can modify either the copy >> or [quoted text clipped - 5 lines] > > Neither the copy nor the original. That was why I was asking. While there are other objects involved, there are a number of Strings involved.
> You can copy a String a couple of ways, e.g., > String original = "Something"; > String copy = new String( original ); Okay, I missed the obvious. Thanks!
Hal
Twisted - 13 Jul 2007 03:06 GMT > > Okay, so how do I make copy of a String so I can modify either the copy or > > the original without effecting [sic] the other? (Yes, I know Strings follow [quoted text clipped - 7 lines] > String original = "Something"; > String copy = new String( original ); And it's pointless. Strings are immutable. Better than copying them, intern them all -- myString = myString.intern();
Now duplicate Strings don't waste extra memory.
Whenever you use String operations to "modify" a String you actually make a mutated copy of the original String; if you have myString = "foo" and then yourString = myString and then myString = myString.append("bar") you end up with myString.equals("foobar") (myString == "foobar" if you intern myString after the append) and yourString == "foo". The old version is still preserved; yourString did not change to "foobar". (Note that interned strings will compare == to one another and to literals, which are automatically interned, when they are equals(). Comparing interned strings can be especially efficient then.)
Regardless, you can just copy the String references when you copy the data structure, and the backup won't change spontaneously because of edits to the original data structure, as long as you don't do anything sneaky with reflection to mutate the Strings in the data structure.
If it's mainly Strings you can probably also find some sensible way to externalize it with writeExternal and read it back with readExternal in an ASCII-based (or unicode, anyway) format. This would be nicer than serialization for this sort of data, and provides a way to both save to disk and (via ByteArrayFooStreams or a temporary file) backup.
Some wag will no doubt now suggest externalizing as XML. XML seems to be the current "hammer fad", which makes everything look like a nail to some people.
Hal Vaughan - 13 Jul 2007 04:34 GMT >> > Okay, so how do I make copy of a String so I can modify either the copy >> > or [quoted text clipped - 36 lines] > than serialization for this sort of data, and provides a way to both > save to disk and (via ByteArrayFooStreams or a temporary file) backup. I'll be looking into this. I've never heard of intern() or writeExternal(). That's more I can explore.
> Some wag will no doubt now suggest externalizing as XML. XML seems to > be the current "hammer fad", which makes everything look like a nail > to some people. XML would be pointless. I'm not saving the data for longer than the program is running. Personally I think XML is overused.
Hal
Hal Vaughan - 22 Jul 2007 08:36 GMT ...
> If that doesn't work, how can I create a backup of an Object so I can > change the values in one while the values in the other stay the same? Thanks to everyone for all the helpful replies. I looked over everything and tried a number of test setups, both to see what would work and to learn more about Java in general. Basically I was working with a class called SedTable (the program is a setting editor, so some of the classes are prefixed by Sed) and SedRow. Within SedTable there was a Vector named fullTable and each element was one SedRow. Within SedRow I had another of my own classes, StringHashMap (I'm avoiding generics and, for now, sticking with what I can use in Java 1.4.2.) I also had other data in each SedRow class, such as a flag to show if a row had been deleted and other flags and metadata.
First I looked at alternatives to Vectors since someone mentioned there were issues with Vectors and they're outdated. (I don't think thread safety is a factor. While this is a Swing interface, once a value is selected or changed, the components are frozen until all the updates are done (which is usually too fast for the user to detect). I changed to using ArrayLists, which took almost no coding change and made a few parts easier. (That's one issue to being self taught -- I learn about one thing that works and don't know there are other structures that work even better.)
In the long run I decided to serialize the objects. I know to some that sounds like a lot of work and it seems preferred to just create copy methods, but memory doesn't seem to be an issue from what I've measured and it took far less code to serialize the objects than to copy them.
Basically I added a backup() method in SedTable that serializes the ArrayList that contains all the SedRows. Then I got an error for SedRow, but all I had to add was "implements Serializable" to the class declaration line. While I was at it, I did the same to my StringHashMap (and shift-ctrl-o fixed the imports in Eclipse). Then it only took a few lines of code to output the object to an OjbectOutPutStream, wrap a ByteArrayOutputStream around it, and have it dump everything into a byte[]. To read it back, I just reversed it and read from the same byte[] with a ByteArrayInputStream with an ObjectInputStream wrapped around it.
I figured if I was going to copy it, I'd have to write a loop in SedTable to go through the ArrayList and call a copy method on each SedRow. Then I'd have to store the StringHashMaps and a few other objects in SedRow. That would be new code in at least 2 classes and extra code for several loops and trying to create backup copies within classes. Another factor, one I didn't realize until I was trying to ride the code, was that people suggested using a copy() constructor, but nobody mentioned how, when using one, I could make sure the new class had new data and not just pointers to the old data. In the long run it was actually easier to serialize. (Add 2 words to several classes and just add a few lines of I/O code to store each ArrayList.)
I found this link extremely helpful in using the serialization:
http://java.sun.com/developer/technicalArticles/Programming/serialization/
I've already tested this and am thrilled with how easily it works.
Hal
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|