Title: Copying Shallow and Deep, Cloning, and ReadOnly Views
1Copying (Shallow and Deep), Cloning, and
Read-Only Views
- Copying (Section 3.4)
- it is common to want to make a "copy" of some
object so another module can manipulate the
object without affecting your data - this "non-interference" is a major premise of
modularity - "copy" has an informal meaning like "you can
alter your copy without affecting mine" but that
can be interpreted in a number of ways - the main question is what can we say about
variable y after executing y x.copy()(for
various definitions of the copy method)
2Copying A Non-Solution
public class Thing public Thing
copy() return this Thing x
new Thing() Thing y x.copy() // Equivalent
to saying // Thing y x
x
y
what relationship should hold between x and
y? what relationship should not hold?
3Copying Primitives A Non-Problem
- "Making a copy" of a primitive data type is a
non-issue, because values of primitives are
stored "immediately" rather than by reference,
and copying is only an issue with regards
references
Thing x new Thing() Thing y x int i
12 int j i
x
y
i
12
j
12
4Shallow Copying
- To make a copy, we need to make a new instance of
the same class on the heap, then make its
internal state (instance variables) "look like"
the original
public class Thing int a String b
Student c public Thing (int a, String b,
Student c) this.a a this.b
b this.c c public Thing
shallowCopy() return new Thing(this.a,
this.b, this.c) public class Student
String name int grade public
Student(String name, int grade) public
void setGrade(int newGrade) this.grade
newGrade
now if Thing y copy(x) -- class of y is the
same as class of x -- y ! x -- it will
typically be the case that
y.equals(x) and that
x.equals(y) why is this called "shallow"?
5Shallow Copy Another Implementation
// Same thing, just a more conventional way of
writing it public class Thing int a
String b Student c private Thing()
public Thing (int a, String b, Student
c) this.a a this.b b
this.c c public Thing
shallowCopy() Thing newThing new
Thing() newThing.a this.a
newThing.b this.b newThing.c this.c
return newThing
6Shallow Copy The Picture
Thing s new Thing(12, "hi", new
Student("Sally", 1) Thing s2 s.shallowCopy()
Heap
Symbol table
a Thing
a String
3
s
hi
s2
3
a Student
Sally 1
a Thing
7Next Idea Deep Copy
- Like shallow copy only "more so"
- the copy is the same class as the original
- the copy is not to the original
- the copy is typically equal to the original
- the copy shares no reference (structure) with the
original
8Deep Copying
- What would a deep copy of s look like?
Thing s new Thing(12, "hi", new
Student("Sally", 1)) Thing s2 s.deepCopy()
3
s
hi
s2
3
Sally 1
9Standard Copy Paradigms
public class Thing int a String b
Student c private Thing()
public Thing (int a, String b, Student c)
this.a a this.b b this.c
c public Thing shallowCopy()
Thing copy new Thing() copy.a
this.a copy.b this.b copy.c
this.c return copy public
Thing deepCopy() Thing copy new
Thing() copy.a this.a.deepCopy()
copy.b this.b.deepCopy() copy.c
this.c.deepCopy()
-- why the red? -- does the deep copy method
guarantee that the copy will share no
reference with the original? -- if not,
under what circumstances could we make that
guarantee -- what does the actual deep copier
for Thing look like?
10A Middle Ground
- Somewhere between shallow copy and deep copy is
"non-mutable" copy - the original and the copy can share structure, as
long as the shared references are of non-mutable
types - what does non-mutable mean?
- what is an example of a non-mutable class?
- why is this an interesting middle ground?
- what is the "non-mutable copier" for the Thing
class?
11Another Common Paradigm The Copy Constructor
- A copy constructor is a constructor that takes a
single parameter, an object as the same type as
the original, and constructs the copy (usually
using shallow copy) - More common in C than in Java, though see the
ArrayList example below
public class Thing int a String b
Student c public Thing (int a, String b,
Student c) this.a a this.b
b this.c c public
Thing(Thing original) this.a
original.a this.b original.b
this.c original.c
Constructor Summary ArrayList(Collection c)
          Constructs a list containing the
elements of the specified collection,
in the order they are returned by the
collection's iterator.
12Java Support for Copying
- First, some classes provide copy constructors
- String s1 "hello"String s2 new String(s1)
- ArrayList a1ArrayList a1 new ArrayList(a1)
- The Collections generally do shallow copying
- what does a shallow copy and a deep copy of a
List look like? - The Java Cloneable interface provides a framework
for implementing a copier
13Java Cloning Framework
- The basic copy paradigm is
- make a new "blank" instance of the object to be
copied - go field by field (instance variable by instance
variable) through the object and assign the value
of the field in the new instance the same value
as in the old instance - return the new instance
- Java should automate that as much as possible
- which means there should be some kind of copy
method defined in the Object class, so every
class could have that functionality - But there also needs to be an ability to
over-ride that default behavior - a class should be able to decide on shallow
versus deep versus non-mutable copy, or any
combination that suits it - First we will look at the Java documentation
14Java Cloning Framework (cont.)
- The main pillar of the framework is the method
protected Object clone()which is defined in
the Object class - This method does the shallow copy all
references (addresses) are duplicated exactly so
there is structure shared - The protected visibility means that an
application program cannot ordinarily call clone - for example Student aNewStudent
aStudent.clone() would result in a compiler
error due to package visibility - If you as a class designer decide you want to use
the framework to implement your "standard"
copy/cloning mechanism (whatever you choose that
to be), you - define your own clone method public Object
clone() which will override the default defined
in class Object - declare that your class implements Cloneable
15The Simplest Example
public class Thing implements Cloneable int
a String b Student c public Thing
(int a, String b, Student c) this.a a
this.b b this.c c public
Object clone() try return
super.clone() catch (CloneNotSupportedExc
eption e) throw new
RuntimeException(e) class
Student String name int grade
public Student(String name, int grade)
this.name name this.grade grade
public void setGrade(int newGrade)
this.grade newGrade
-- notice the need to handle the possibility
that the superclass doesn't support the
clone() operation -- notice that Student doesn't
implement the clone() operation, will that
cause an error? -- how could we tell what
the relationship is between t1 and t2?
public static void main(String args) Thing
t1 new Thing( 1,
"hi", new Student("Sally", 1))
Thing t2 (Thing)t1.clone()
16Cloning To Do a Deep Copy
public class Thing implements Cloneable int
a String b Student c // Constructor
omitted public Object clone() try
Thing newThing (Thing)super.clone()
newThing.b new String(this.b) newThing.c
(Student)this.c.clone() return
newThing catch (CloneNotSupportedException
e) throw new RuntimeException(e)
class Student implements Cloneable String
name int grade // Constructor and setter
omitted public Object clone() try
Student newStudent (Student)super.clone()
newStudent.name new String(this.name)
return newStudent catch
(CloneNotSupportedException e) throw new
RuntimeException(e)
17Cloning to do a Non-Mutable Copy
- Remember the definition of non-mutable the
original object and the copy can share structure,
as long as none of the objects they share are
mutable - How to alter the Thing/Student code so it does a
non-mutable copy instead of a deep copy?
18Copying versus Read-Only View
- Let's remember why we want to make a copy of
something in the first place - For the Course class
- I will give you a copy of the class list, and you
can mark it up however you like (the deep copy) - I will let you look at my copy of the class list,
but you cannot change it in any way (a read-only
view on the original) - If you decide that a read-only view is
acceptable, all of the copy issues go away. You
have two options - provide an unmodifiable collection view on the
collection - provide an iterator over the collection, but that
does not allow the remove() method
19Unmodifiable Collections
- A very simple concept take a collection (a Set,
a List, or a Map) and "wrap around it" an object
that - "passes through" all the query requests
- throws an exception on all the mutating requests
- Notice that this "wrapper object" still
implements the Set or List or Map interface in
that it will handle a clear or remove method call - it will just handle it by throwing an exception
- and the side point is that "implementing an
interface" is something decided by the compiler,
and only means "every method in the interface is
implemented as a public method by the class" - Look at the Collections abstract class and the
unmodifiableSet method - Look at our old Course/Student code and show how
to produce a read-only view on the collection
20Unmodifiable Iterators
- The concept is much the same
- Many times we provide access to collection
classes by supplying an iterator over its
elements (anArrayList.iterator()
aHashSet.iterator()) - The iterator allows modification of the
underlying collection because it supports the
remove method - So what we do is "wrap" the iterator in a class
that - "passes through" all the query requests (hasNext
and next) - throws an exception on all the mutating requests
(remove) - Java does not have this built in, so we will have
to do it ourselves - first write the basic class
- then apply it to the Course/Student project