| Copying and Equality |
| copying |
| Copying |
| Suppose we want to make a copy of an
object with the following structure: class MyClass { OpenList List1, List2; } |
| Ways to Copy |
| Copy constructor | |
| static copy method | |
| clone() method (returns copy) | |
| Any of these can be defined in terms of the other. | |
| Copy constructor |
| Add constructor MyClass(MyClass orig) { É } |
|
| Use constructor MyClass newObj = new MyClass(orig); |
| static copy method |
| Add method static MyClass copy(MyClass orig) { É } |
|
| Use method MyClass newObj = MyClass.copy(orig); |
| clone() method |
| Add method public MyClass clone() { É } |
|
| Use method MyClass newObj = orig.clone(); |
| Body of copy method, etc. |
| Various meanings of ÒcopyÓ | ||
| Think of object as a tree | ||
| Deep copy: Copy all the way down to the leaves. | ||
| Shallow copy: Copy references only. | ||
| Illustrate with copy constructors | ||
| Shallow Copy |
| class MyClass { OpenList List1, List2; MyClass(MyClass orig) { List1 = orig.List1; List2 = orig.List2; } } |
|
| The copy shares the lists with the original. |
| Deep Copy |
| class MyClass { OpenList List1, List2; MyClass(MyClass orig) { List1 = copyOpenList(orig.List1); List2 = copyOpenList(orig.List2); } } |
|
| The copy has copies of the original lists, provided that copyList makes such copies. |
| copyList, slightly deeper |
| static OpenList copyOpenList(OpenList
orig) { if( orig.isEmpty() ) { return OpenList.nil; } else { return cons(orig.first(), copyOpenList(orig.rest())); } } |
|
| Still does not copy individual list elements (which could be lists themselves). |
| copyList, with copied Elements |
| static OpenList copyOpenList(OpenList
orig) { if( orig.isEmpty() ) { return OpenList.nil; } else { return cons(copy(orig.first()), copyOpenList(orig.rest())); } } |
|
| Copying elements that are lists recursively |
| clone() |
| clone() is defined for every object. | |
| It is over-ridable. | |
| There is an interface Cloneable: to
over-ride clone() a class must declare that it implements Cloneable |
|
| To get an Object to clone itself, Java
says to return: super.Clone() |
|
| If the Object is not Cloneable, it will
throw CloneNotSupportedException |
|
| clone() limitations |
| You cannot do this: as clone() is not visible for Objects in general. |
|
| I could find no way to implement a general static method that will check dynamically whether an Object implements Cloneable, then call clone(). There may be a kludgy way. | |
| Checking Equality |
| Defining equals() is at programmerÕs discretion | ||
| By analogy with copying: | ||
| Equality checking can be deep or shallow. | ||
| Semantic equality may be taken into account: | ||
| e.g. allowing an integer value to be equal to a floating value. | ||
| Default equals() |
| equals() is defined in the base class Object. | |
| It may/should be over-ridden. | |
| The default implementation is that
x.equals(y) if, and only if, x and y are the same Object. |
| Interning principle |
| Suppose we could guarantee that two objects are semantically equal only if they are the same object. | |
| Then computing equals would be very fast: only need to compare references. | |
| Such a guarantee can be made if we intern all of the objects in the class. |
| Interning principle |
| To intern objects in a class, we need a way to get to all objects in that class that were ever created. | ||
| The client does not use the constructor, but rather uses a factory method that returns objects. | ||
| The factory method checks to see whether the prescribed object has already been created | ||
| If so, it returns the existing objectÕs reference. | ||
| If not, it creates a new object (using the constructor) and returns the reference to that object. | ||
| Interning Example: an Interning cons |
| Implementing find and remember |
| We must store every OpenList ever produced (sharing tails, etc.) | |
| We must be able to find a list with equal firsts and rests. | |
| A na•ve implementation would store an internal list of all OpenLists (not itself a OpenList) and search the list with find. | |
| This process can become slow. |
| Faster Implemention of find and remember |
| Use the concept of hashing. | |
| Hashing computes a numeric signature for the proposed new item. | |
| It then uses the signature to access an array (called a hash table) of Òequivalence classesÓ of items. | |
| Each equivalence class ideally has a relatively small number of items in it. | |
| The only searching needed is that of searching the small equivalence class, not the whole universe. |
| How Java Helps |
| Java provides method hashCode() of Object. | |
| This gives a (generally large) number for any object. | |
| By dividing the hash code by the hash table size, equivalence classes are thereby formed. | |
| All objects with the same hash code modulo the table size are considered equivalent. | |
| Java also provides a class HashSet that can be used to implement find and remember. |
| Further Investigation |
| Examine these classes/interfaces on the Java API web page: | ||
| Exception | ||
| Object | ||
| Cloneable | ||
| HashSet | ||
| Collection | ||
| HashMap | ||