Java Forum / First Aid / June 2005
Question about clone a Hashtable
George George - 15 May 2005 10:49 GMT Hello everyone,
I want to clone the content of a Hashtable (its keys, its values and its key-value relationship). But I have found that the clone method can not completely clone a Hashtable, as is mentioned in the description of clone method of Java API Specification,
Creates a shallow copy of this hashtable. All the structure of the hashtable itself is copied, but the keys and values are not cloned. This is a relatively expensive operation.
I am wondering what is the efficient and effective approach of cloning a Hashtable, including the clone of its keys, its values and its key-value relationship.
Thanks in advance, George
ByteCoder - 15 May 2005 11:58 GMT > Hello everyone, > [quoted text clipped - 13 lines] > Thanks in advance, > George Perhaps something like this would work (correct me if I'm wrong):
HashTable clone = originalHashTable;
 Signature ------------- - ByteCoder - ...I see stupid people ------------- Curiosity *Skilled* the cat
Tony Morris - 15 May 2005 12:23 GMT > > Hello everyone, > > [quoted text clipped - 17 lines] > > HashTable clone = originalHashTable; Yes, that is wrong. It will perform a reference assignment, and nothing more. Cloning a Hashtable is indicative of something seriously broken, and due to the common misconception to the contrary, I won't bother justifying the assertion for fear of boring, useless internet arguments.
 Signature Tony Morris Software Engineer, IBM Australia. BInfTech, SCJP 1.4, SCJP 5.0, SCJD
http://www.jtiger.org/ JTiger Unit Test Framework for Java http://qa.jtiger.org/ Java Q&A (FAQ, Trivia) http://xdweb.net/~dibblego/
ByteCoder - 15 May 2005 14:11 GMT >> > Hello everyone, >> > [quoted text clipped - 24 lines] > justifying the assertion for fear of boring, useless internet > arguments. Thank you for pointing that out to me. So you're actually saying there is no really no proper way to clone a HashSet?
Actually, you could create a new HastSet and copy each item from the old HashSet to the new one. Granted, it's not as fast as 'cloning' it, but it should work.
 Signature ------------- - ByteCoder - ...I see stupid people ------------- Curiosity *Skilled* the cat
George George - 16 May 2005 07:57 GMT Thanks Tony,
I have written a simple sample below, but from the sample's output, I have found out that it seems that the clone method of Hashtable copies the the content of both keys and values, not as mentioned in the Java API specification of clone method of class Hashtable "but the keys and values are not cloned".
Do you know what points do the Java specification mean?
[Code] Hashtable table1 = new Hashtable(); table1.put ("key1", "value1"); Hashtable table2 = (Hashtable) table1.clone(); if (table2.containsKey ("key1")) { System.out.println ("Contains!"); table2.put ("key1", "value2"); String newValue1 = (String) table1.get ("key1"); System.out.println ("New value1 of table1: " + newValue1); newValue1 = (String) table2.get ("key1"); System.out.println ("New value1 of table2: " + newValue1); } else { System.out.println ("Not contains!"); } [/Code]
Output is:
Contains! New value1 of table1: value1 New value1 of table2: value2
regards, George
G Winstanley - 09 Jun 2005 02:48 GMT > Thanks Tony, > [quoted text clipped - 33 lines] > regards, > George The clone() method creates new references to the same objects that are used as keys/values for the original. All you are achieving is assigning a different object to the same key.
Forgive my poor ASCII art, but this is roughly what I mean:
Original -------- Hashtable1 Key1 -------------> "key1" <------ Value1 -----------> "value1" <- | Hashtable2 | | Key1 -------------------------)--- Value1 -----------------------
Modified -------- Hashtable1 Key1 -------------> "key1" <------ Value1 -----------> "value1" | Hashtable2 | Key1 ----------------------------- Value1 -----------> "value2"
Stan
George George - 09 Jun 2005 08:49 GMT Thanks Stan,
>> Thanks Tony, >> [quoted text clipped - 27 lines] > >Stan What do you mean "All you are achieving is assigning a different object to the same key"? Could you please provide a sample program to illustrate your idea?
regards, George
G Winstanley - 10 Jun 2005 13:18 GMT > Thanks Stan, > [quoted text clipped - 36 lines] > regards, > George Sure. This illustrates a bit of both...
import java.util.*;
public class HashCloneTest { public static void main(String[] args) { Hashtable table1 = new Hashtable(); Thing x = new Thing(1); table1.put("key", x); System.out.println("table1: " + table1.get("key"));
Hashtable table2 = (Hashtable)table1.clone(); System.out.println("table2: " + table2.get("key"));
((Thing)table1.get("key")).setNum(2); System.out.println("table1: " + table1.get("key")); System.out.println("table2: " + table2.get("key"));
table2.put("key", new Thing(3)); System.out.println("table2: " + table2.get("key")); } private static final class Thing { private int num; private Thing(int i) { setNum(i); } private void setNum(int i) { this.num = i; } public String toString() { return "Thing[" + num + "]"; } } }
Stan
George George - 12 Jun 2005 12:45 GMT Thanks Stan,
>> Thanks Stan, >> [quoted text clipped - 36 lines] > >Stan Your sample is very helpful. I think in your sample you mean the clone method of Hashtable only copies the reference of value objects from the original Hashtable to the new cloned Hashtable, and do not create new objects for value objects in a new cloned Hashtable. Am I correct?
regards, George
G Winstanley - 14 Jun 2005 03:50 GMT > Thanks Stan, > [quoted text clipped - 46 lines] > regards, > George Yes, that's what I mean. This system of shallow-copying is done is many places in the JDK/JRE, notably in the Collection classes. Implementations of deep-cloning (other than esoteric implementations like Serialization) need to be hand-crafted by those who desire it.
Stan
George George - 15 Jun 2005 03:53 GMT Thanks Stan,
>> Thanks Stan, >> [quoted text clipped - 8 lines] > >Stan Your reply is very helpful. Why do you say the implementation of Serialization is esoteric? I am very interested in how Serialization implements deep-cloning. Could you please describe how deep-cloning of Serialization is working, or recommend me some online resources (tutorials or papers) dealing with this topic?
regards, George
G Winstanley - 17 Jun 2005 01:14 GMT > Thanks Stan, > [quoted text clipped - 19 lines] > regards, > George It simply goes way beyond the scope of the deep-cloning most users need for everyday purposes. Most programmers will simply need to implement deep-cloning as far as their application requires, which is often reasonably simple. Serialization requires compatability with almost every class out there, and rigorous circularity checking, and version control, etc. so is esoteric in the sense that it's beyond the simple implementation most will require. If you're really interested in it's implementation go and look at the source. java.io.ObjectOutputStream.java in src.zip should be a good place to start. Enjoy.
Stan
George George - 17 Jun 2005 04:07 GMT Thanks Stan,
>> Thanks Stan, >> [quoted text clipped - 13 lines] > >Stan Your reply is just what I am looking for.
Have a nice weekend, George
Robert Maas, see http://tinyurl.com/uh3t - 11 Jun 2005 05:01 GMT > From: "George George via JavaKB.com" <forum@nospam.JavaKB.com> > I want to clone the content of a Hashtable (its keys, its values and [quoted text clipped - 3 lines] > shallow copy of this hashtable. All the structure of the hashtable > itself is copied, but the keys and values are not cloned. ... There are only three "canonical" copy operations possible: - Copying the reference (pointer) but don't copy any of the structure. (Java does this by simple assignment of pointer variables) - Copy the structure of the container itself, but just copy references to all components within the container. (This is the shallow copy you are referring to.) - Copy all the structure as deep as it goes. Unfortunately there can be pointer loops, so if you do this by simple recursive algorithm you get a recursive loop causing stack overflow. Java solves this in the serialization mechanism by building a hash table of all items copied and when it encounters a pointer to an item already in the table it makes a back-reference instead of copying it a second time. (If this is the behaviour you want, why don't you just serialize to a string then deserialize back to a new structure which is an isomorphic copy of the original?)
If you want anything more than a shallow copy but less than a full deep serialization, how do you expect Java to guess what you want?? You should write your own class which sub-classes Hashtable, and define whatever kind of very-deep-but-not-all-the-way cloning you want.
By the way, for enlightenment, you really should read this: Linkname: P.S.: The Best of Intentions URL: http://www.nhplace.com/kent/PS/EQUAL.html It's from the point of view of lisp, but it applies equally well to java.
George George - 12 Jun 2005 13:03 GMT Thanks Robert,
>- Copy all the structure as deep as it goes. Unfortunately there can be > pointer loops, so if you do this by simple recursive algorithm you [quoted text clipped - 5 lines] > string then deserialize back to a new structure which is an isomorphic > copy of the original?) From your reply, I think you are a real expert in copy related field. :-) I have a question from your reply. I do not quite understand how Java uses serialization to make deep copy. Do you mean copy operation will invoke serialization method internally in JVM?
It seems that Java uses a hash table and back-reference to solve the stack overflow issue in traditional simple recursive algorithm (but I can not see clearly how these methods could solve stack overflow issue, since in my understanding of your reply, we still use hash table, back-reference together with recursive algorithm, so recursive algorithm is still used and stack overflow may still occur). I am very interested in this point. Could you please explain it in more details or provide me some resources on this topic?
regards, George
Robert Maas, see http://tinyurl.com/uh3t - 26 Jun 2005 03:07 GMT > From: "George George via JavaKB.com" <forum@JavaKB.com> > I do not quite understand how Java uses serialization to make deep > copy. Do you mean copy operation will invoke serialization method > internally in JVM? No. You get a serialization (first half of total copy) only when you explicitly write data to a serialized-object stream. http://java.sun.com/j2se/1.3/docs/api/java/io/ObjectOutputStream.html Then the second half of the totally-deep copy operation occurs when the stream is used to reconstitute an object in a new location: http://java.sun.com/j2se/1.3/docs/api/java/io/ObjectInputStream.html
> It seems that Java uses a hash table and back-reference to solve the > stack overflow issue in traditional simple recursive algorithm (but I > can not see clearly how these methods could solve stack overflow issue, > since in my understanding of your reply, we still use hash table, > back-reference together with recursive algorithm, so recursive > algorithm is still used and stack overflow may still occur). The reason why stack overflow is *sure* to happen if you try to use a naive recursive algorithm to copy a structure that contains a pointer-loop is that you recurse deeper and deeper to keep encountering that same loop over and over and over, never finding any bottom to the structure so never returning from recursion. For example, imagine a simple structure with two nodes, each of which points to the other: A <==> B So you start at A, copy that, see pointer to B so you recurse into B to copy that, and see pointer to A and recurse into that to copy A, and see pointer to B but fail to notice you already followed that pointer so you recurse into B again, etc. back and forth deeper and deeper until the stack overflows. At some point you've copied: A -> B -> A1 -> B1 -> A2 -> B2 -> A3 -. B3 -> ... many copies of each node and each direction of link, when stack overflows.
If you keep a list of all nodes already visited, and never copy the same node more than once, and never copy the same link more than once, it works like this: Start at A, put A into table, see link to B, copy link, see B is new node, put B into table, copy B, see link to A, copy link, see A already in table, back off recursion to B, see no more links from B, back off to A, see no more links from A, back out of top level of recursion.
The only way such a table-keeping algorithm can get stack overflow is if you really do have a very very very long chain of links, which wouldn't happen in any reasonable program except if you make a linked list to hold a very large list which is possibly unreasonable in the first place. Instead of a very very very long linked list, it's probably better to keep the data in a balanced binary tree of some sort, so then a list of n elements requires only log(n) stack depth to copy it all. For example, see: http://java.sun.com/j2se/1.3/docs/api/java/util/TreeSet.html http://java.sun.com/j2se/1.3/docs/api/java/util/TreeMap.html
George George - 29 Jun 2005 03:19 GMT Thanks Robert,
>If you keep a list of all nodes already visited, and never copy the >same node more than once, and never copy the same link more than once, [quoted text clipped - 3 lines] >links from B, back off to A, see no more links from A, back out of top >level of recursion. Your reply is very great! I am wondering where can I find some formal tutorials or documents dealing with the copy algorithm? Are there any open source algorithm implementations?
regards, George
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 ...
|
|
|