📄 tij319.htm
字号:
});
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><p><br></p>
<p><b>Int3</b> is inherited from <b>Int2</b>, and a new primitive member, <b>int j</b>,<b> </b>is added. You might think that you’d need to override <b>clone( )</b> again to make sure <b>j</b> is copied, but that’s not the case. When <b>Int2</b>’s <b>clone( )</b> is called as <b>Int3</b>’s <b>clone( )</b>, it calls <b>Object.clone( ),</b> which determines that it’s working with an <b>Int3</b> and duplicates all the bits in the <b>Int3</b>. As long as you don’t add references that need to be cloned, the one call to <b>Object.clone( )</b> performs all of the necessary duplication regardless of how far down in the hierarchy <b>clone( )</b> is defined. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2732" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>You can see what’s necessary in order to do a deep copy of an <b>ArrayList</b>: After the <b>ArrayList</b> is cloned, you have to step through and clone each one of the objects pointed to by the <b>ArrayList</b>. You’d have to do something similar to this to do a deep copy of a <b>HashMap</b>. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2733" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>The remainder of the example shows that the cloning did happen by showing that, once an object is cloned, you can change it, and the original object is left untouched. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2734" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc375545429"></a><a name="_Toc24775999"></a><a name="Heading24970"></a>Deep
copy via serialization</h3>
<p>When you consider Java’s object serialization (introduced in Chapter 12), you might observe that an object that’s serialized and then deserialized is, in effect, cloned. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2735" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>So why not use serialization to perform deep copying? Here’s an example that compares the two approaches by timing them:<br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: appendixa:Compete.java</font>
<font color=#0000ff>import</font> java.io.*;
<font color=#0000ff>class</font> Thing1 <font color=#0000ff>implements</font> Serializable {}
<font color=#0000ff>class</font> Thing2 <font color=#0000ff>implements</font> Serializable {
Thing1 o1 = <font color=#0000ff>new</font> Thing1();
}
<font color=#0000ff>class</font> Thing3 <font color=#0000ff>implements</font> Cloneable {
<font color=#0000ff>public</font> Object clone() {
Object o = <font color=#0000ff>null</font>;
<font color=#0000ff>try</font> {
o = <font color=#0000ff>super</font>.clone();
} <font color=#0000ff>catch</font>(CloneNotSupportedException e) {
System.err.println(<font color=#004488>"Thing3 can't clone"</font>);
}
<font color=#0000ff>return</font> o;
}
}
<font color=#0000ff>class</font> Thing4 <font color=#0000ff>implements</font> Cloneable {
<font color=#0000ff>private</font> Thing3 o3 = <font color=#0000ff>new</font> Thing3();
<font color=#0000ff>public</font> Object clone() {
Thing4 o = <font color=#0000ff>null</font>;
<font color=#0000ff>try</font> {
o = (Thing4)<font color=#0000ff>super</font>.clone();
} <font color=#0000ff>catch</font>(CloneNotSupportedException e) {
System.err.println(<font color=#004488>"Thing4 can't clone"</font>);
}
<font color=#009900>// Clone the field, too:</font>
o.o3 = (Thing3)o3.clone();
<font color=#0000ff>return</font> o;
}
}
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Compete {
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>final</font> <font color=#0000ff>int</font> SIZE = 25000;
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) <font color=#0000ff>throws</font> Exception {
Thing2[] a = <font color=#0000ff>new</font> Thing2[SIZE];
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < a.length; i++)
a[i] = <font color=#0000ff>new</font> Thing2();
Thing4[] b = <font color=#0000ff>new</font> Thing4[SIZE];
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < b.length; i++)
b[i] = <font color=#0000ff>new</font> Thing4();
<font color=#0000ff>long</font> t1 = System.currentTimeMillis();
ByteArrayOutputStream buf= <font color=#0000ff>new</font> ByteArrayOutputStream();
ObjectOutputStream o = <font color=#0000ff>new</font> ObjectOutputStream(buf);
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < a.length; i++)
o.writeObject(a[i]);
<font color=#009900>// Now get copies:</font>
ObjectInputStream in = <font color=#0000ff>new</font> ObjectInputStream(
<font color=#0000ff>new</font> ByteArrayInputStream(buf.toByteArray()));
Thing2[] c = <font color=#0000ff>new</font> Thing2[SIZE];
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < c.length; i++)
c[i] = (Thing2)in.readObject();
<font color=#0000ff>long</font> t2 = System.currentTimeMillis();
System.out.println(<font color=#004488>"Duplication via serialization: "</font> +
(t2 - t1) + <font color=#004488>" Milliseconds"</font>);
<font color=#009900>// Now try cloning:</font>
t1 = System.currentTimeMillis();
Thing4[] d = <font color=#0000ff>new</font> Thing4[SIZE];
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < d.length; i++)
d[i] = (Thing4)b[i].clone();
t2 = System.currentTimeMillis();
System.out.println(<font color=#004488>"Duplication via cloning: "</font> +
(t2 - t1) + <font color=#004488>" Milliseconds"</font>);
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><p><br></p>
<p><b>Thing2</b> and <b>Thing4</b> contain member objects so that there’s some deep copying going on. It’s interesting to notice that while <b>Serializable</b> classes are easy to set up, there’s much more work going on to duplicate them. Cloning involves a lot of work to set up the class, but the actual duplication of objects is relatively simple. The results are interesting. Here is the output from three different runs:<br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Duplication via serialization: 547 Milliseconds
Duplication via cloning: 110 Milliseconds
Duplication via serialization: 547 Milliseconds
Duplication via cloning: 109 Milliseconds
Duplication via serialization: 547 Milliseconds
Duplication via cloning: 125 Milliseconds</PRE></FONT></BLOCKQUOTE><p><br></p>
<p>In earlier versions of the JDK, the time required for serialization was much longer than that of cloning (roughly 15 times slower), and the serialization time tended to vary a lot. More recent versions of the JDK have sped up serialization and apparently made the time more consistent, as well. Here, it’s approximately four times slower, which brings it into the realm of reasonability for use as a cloning alternative. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2736" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc24776000"></a><a name="Heading25053"></a>Adding cloneability
<br>farther down a hierarchy</h3>
<p>If you create a new class, its base class defaults to <b>Object</b>, which defaults to noncloneability (as you’ll see in the next section). As long as you don’t explicitly add cloneability, you won’t get it. But you can add it in at any layer and it will then be cloneable from that layer downward, like this:<br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: appendixa:HorrorFlick.java</font>
<font color=#009900>// You can insert Cloneability at any level of inheritance.</font>
<font color=#0000ff>package</font> appendixa;
<font color=#0000ff>import</font> java.util.*;
<font color=#0000ff>class</font> Person {}
<font color=#0000ff>class</font> Hero <font color=#0000ff>extends</font> Person {}
<font color=#0000ff>class</font> Scientist <font color=#0000ff>extends</font> Person <font color=#0000ff>implements</font> Cloneable {
<font color=#0000ff>public</font> Object clone() {
<font color=#0000ff>try</font> {
<font color=#0000ff>return</font> <font color=#0000ff>super</font>.clone();
} <font color=#0000ff>catch</font>(CloneNotSupportedException e) {
<font color=#009900>// This should never happen: It's Cloneable already!</font>
<font color=#0000ff>throw</font> <font color=#0000ff>new</font> RuntimeException(e);
}
}
}
<font color=#0000ff>class</font> MadScientist <font color=#0000ff>extends</font> Scientist {}
<font color=#0000ff>public</font> <font color=#0000ff>class</font> HorrorFlick {
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Person p = <font color=#0000ff>new</font> Person();
Hero h = <font color=#0000ff>new</font> Hero();
Scientist s = <font color=#0000ff>new</font> Scientist();
MadScientist m = <font color=#0000ff>new</font> MadScientist();
<font color=#009900>//! p = (Person)p.clone(); // Compile error</font>
<font color=#009900>//! h = (Hero)h.clone(); // Compile error</font>
s = (Scientist)s.clone();
m = (MadScientist)m.clone();
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><p><br></p>
<p>Before cloneability was added in the hierarchy, the compiler stopped you from trying to clone things. When cloneability is added in <b>Scientist</b>, then <b>Scientist</b> and all its descendants are cloneable. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2737" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc375545430"></a><a name="_Toc24776001"></a><a name="Heading25088"></a>Why
this strange design?</h3>
<p>If all this seems to be a strange scheme, that’s because it is. You might wonder why it worked out this way. What is the meaning behind this design? <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2738" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Originally, Java was designed as a language to control hardware boxes, and definitely not with the Internet in mind. In a general-purpose language like this, it makes sense that the programmer be able to clone any object. Thus, <b>clone( )</b> was placed in the root class <b>Object</b>, <i>but</i> it was a <b>public</b> method so you could always clone any object. This seemed to be the most flexible approach, and after all, what could it hurt? <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2739" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>Well, when Java was seen as the ultimate Internet programming language, things changed. Suddenly, there are security issues, and of course, these issues are dealt with using objects, and you don’t necessarily want anyone to be able to clone your security objects. So what you’re seeing is a lot of patches applied on the original simple and straightforward scheme: <b>clone( )</b> is now <b>protected</b> in <b>Object</b>. You must override it <i>and</i> <b>implement Cloneable</b> <i>and</i> deal with the exceptions. <font size="-2"><a href="mailto:TIJ3@
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -