📄 chapter12.html
字号:
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=#0000ff>catch</font>(Exception e) {
e.printStackTrace();
}
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><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 really tell the tale. Here is the
output from three different runs:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Duplication via serialization: 3400 Milliseconds
Duplication via cloning: 110 Milliseconds
Duplication via serialization: 3410 Milliseconds
Duplication via cloning: 110 Milliseconds
Duplication via serialization: 3520 Milliseconds
Duplication via cloning: 110 Milliseconds</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Despite the obviously huge time
difference between serialization and cloning, you’ll also notice that the
serialization technique seems to vary significantly in its duration, while
cloning takes the same amount of time every
time.</FONT><A NAME="_Toc408018665"></A><BR></P></DIV>
<A NAME="Heading377"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Adding cloneability <BR>further down a hierarchy</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you create a new class, its base
class defaults to <B>Object</B>, which defaults to non-clonability (as
you’ll see in the next section). As long as you don’t explicitly add
clonability, you won’t get it.
<A NAME="Index1480"></A><A NAME="Index1481"></A>But you can add it in at any
layer and it will then be cloneable from that layer downward, like
this:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: HorrorFlick.java</font>
<font color=#009900>// You can insert Cloneability at any</font>
<font color=#009900>// level of inheritance.</font>
<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:</font>
<font color=#009900>// It's Cloneable already!</font>
<font color=#0000ff>throw</font> <font color=#0000ff>new</font> InternalError();
}
}
}
<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>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Before clonability was added, the
compiler stopped you from trying to clone things. When clonability is added in
<B>Scientist</B>, then <B>Scientist</B> and all its descendants are
cloneable.</FONT><A NAME="_Toc375545430"></A><A NAME="_Toc408018666"></A><BR></P></DIV>
<A NAME="Heading378"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Why this strange design?</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">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? What follows is not a substantiated
story – probably because much of the marketing around Java makes it out to
be a perfectly-designed language – but it does go a long way toward
explaining how things ended up the way they did.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">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><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">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><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It’s worth noting that you
must use the <B>Cloneable</B> interface <I>only </I>if you’re going to
call <B>Object</B>’s <B>clone( )</B>, method, since that method
checks at run-time to make sure that your class implements <B>Cloneable</B>. But
for consistency (and since <B>Cloneable</B> is empty anyway) you should
implement
it.</FONT><A NAME="_Toc375545431"></A><A NAME="_Toc408018667"></A><BR></P></DIV>
<A NAME="Heading379"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Controlling cloneability</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You might suggest that, to remove
<A NAME="Index1482"></A><A NAME="Index1483"></A>clonability, the
<B>clone( )</B> method simply be made <B>private</B>, but this won’t
work since you cannot take a base-class method and make it more <B>private</B>
in a derived class. So it’s not that simple. And yet, it’s necessary
to be able to control whether an object can be cloned. There are actually a
number of attitudes you can take to this in a class that you
design:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Georgia"> Indifference. You don’t do anything about
cloning, which means that your class can’t be cloned but a class that
inherits from you can add cloning if it wants. This works only if the default
<B>Object.clone( )</B> will do something reasonable with all the fields in
your class.</FONT><LI><FONT FACE="Georgia"> Support <B>clone( )</B>.
Follow the standard practice of implementing <B>Cloneable</B> and overriding
<B>clone( )</B>. In the overridden <B>clone( )</B>, you call
<B>super.clone( ) </B>and catch all exceptions (so your overridden
<B>clone( )</B> doesn’t throw any
exceptions).</FONT><LI><FONT FACE="Georgia"> Support cloning
conditionally. If your class holds handles to other objects that might or might
not be cloneable (an example of this is a collection class), you can try to
clone all of the objects that you have handles to as part of your cloning, and
if they throw exceptions just pass them through. For example, consider a special
sort of <B>Vector</B> that tries to clone all the objects it holds. When you
write such a <B>Vector</B>, you don’t know what sort of objects the client
programmer might put into your <B>Vector</B>, so you don’t know whether
they can be cloned.</FONT><LI><FONT FACE="Georgia"> Don’t implement
<B>Cloneable</B> but override <B>clone( )</B> as <B>protected</B>,
producing the correct copying behavior for any fields. This way, anyone
inheriting from this class can override <B>clone( )</B> and call
<B>super.clone( )</B> to produce the correct copying behavior. Note that
your implementation can and should invoke <B>super.clone( )</B> even though
that method expects a <B>Cloneable</B> object (it will throw an exception
otherwise), because no one will directly invoke it on an object of your type. It
will get invoked only through a derived class, which, if it is to work
successfully, implements
<B>Cloneable</B>.</FONT><LI><FONT FACE="Georgia"> Try to prevent cloning
by not implementing <B>Cloneable</B> and overriding <B>clone( )</B> to
throw an exception. This is successful only if any class derived from this calls
<B>super.clone( )</B> in its redefinition of <B>clone( )</B>.
Otherwise, a programmer may be able to get around
it.</FONT><LI><FONT FACE="Georgia"> Prevent cloning by making your class
<B>final</B>. If <B>clone( )</B> has not been overridden by any of your
ancestor classes, then it can’t be. If it has, then override it again and
throw <B>CloneNotSupportedException</B>. Making the class <B>final </B>is the
only way to guarantee that cloning is prevented. In addition, when dealing with
security objects or other situations in which you want to control the number of
objects created you should make all constructors <B>private</B> and provide one
or more special methods for creating objects. That way, these methods can
restrict the number of objects created and the conditions in which they’re
created. (A particular case of this is the <I>singleton</I> pattern shown in
Chapter
16.)</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s an
example that shows the various ways cloning can be implemented and then, later
in the hierarchy, “turned off:”</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: CheckCloneable.java</font>
<font color=#009900>// Checking to see if a handle can be cloned</font>
<font color=#009900>// Can't clone this because it doesn't</font>
<font color=#009900>// override clone():</font>
<font color=#0000ff>class</font> Ordinary {}
<font color=#009900>// Overrides clone, but doesn't implement</font>
<font color=#009900>// Cloneable:</font>
<font color=#0000ff>class</font> WrongClone <font color=#0000ff>extends</font> Ordinary {
<font color=#0000ff>public</font> Object clone()
<font color=#0000ff>throws</font> CloneNotSupportedException {
<font color=#0000ff>return</font> <font color=#0000ff>super</font>.clone(); <font color=#009900>// Throws exception</font>
}
}
<font color=#009900>// Does all the right things for cloning:</font>
<font color=#0000ff>class</font> IsCloneable <font color=#0000ff>extends</font> Ordinary
<font color=#0000ff>implements</font> Cloneable {
<font color=#0000ff>public</font> Object clone()
<font color=#0000ff>throws</font> CloneNotSupportedException {
<font color=#0000ff>return</font> <font color=#0000ff>super</font>.clone();
}
}
<font color=#009900>// Turn off cloning by throwing the exception:</font>
<font color=#0000ff>class</font> NoMore <font color=#0000ff>extends</font> IsCloneable {
<font color=#0000ff>public</font> Object clone()
<font color=#0000ff>throws</font> CloneNotSupportedException {
<font color=#0000ff>throw</font> <font color=#0000ff>new</font> CloneNotSupportedException();
}
}
<font color=#0000ff>class</font> TryMore <font color=#0000ff>extends</font> NoMore {
<font color=#0000ff>public</font> Object clone()
<font color=#0000ff>throws</font> CloneNotSupportedException {
<font color=#009900>// Calls NoMore.clone(), throws exception:</font>
<font color=#0000ff>return</font> <font color=#0000ff>super</font>.clone();
}
}
<font color=#0000ff>class</font> BackOn <font color=#0000ff>extends</font> NoMore {
<font color=#0000ff>private</font> BackOn duplicate(BackOn b) {
<font color=#009900>// Somehow
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -