📄 tij0127.html
字号:
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>protected</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and thereby accessible in derived classes.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
figures out how big the object is, creates enough memory for a new one, and
copies all the bits from the old to the new. This is called a <A NAME="Index1460"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>bitwise
copy
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and is typically what you’d expect a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method to do. But before
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
performs its operations, it first checks to see if a class is
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
that is, whether it implements the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
interface. If it doesn’t,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
throws a <A NAME="Index1461"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CloneNotSupportedException</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
to indicate that you can’t clone it. Thus, you’ve got to surround
your call to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
with a try-catch block, to catch an exception that should never happen (because
you’ve implemented the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
interface).
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>LocalCopy</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
the two methods
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>g( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>f( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
demonstrate the difference between the two approaches for argument passing.
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>g( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
shows passing by reference in which it modifies the outside object and returns
a reference to that outside object, while
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>f( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
clones the argument, thereby decoupling it and leaving the original object
alone. It can then proceed to do whatever it wants, and even to return a handle
to this new object without any ill effects to the original. Notice the somewhat
curious-looking statement:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">v
= (MyObject)v.clone();
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
is where the local copy is created. To prevent confusion by such a statement,
remember that this rather strange coding idiom is perfectly feasible in Java
because everything that has a name is actually a handle. So the handle
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>v</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is used to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
a copy of what it refers to, and this returns a handle to the base type
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(because it’s defined that way in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
that must then be cast to the proper type.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>main( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
the difference between the effects of the two different argument-passing
approaches in the two different methods is tested. The output is:
</FONT><P></DIV>
<font color="#990000"><PRE>a == b
a = 12
b = 12
c != d
c = 47
d = 48 </PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">It’s
important to notice that the equivalence tests in Java do not look inside the
objects being compared to see if their values are the same. The <A NAME="Index1462"></A><A NAME="Index1463"></A><A NAME="Index1464"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>==</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>!=</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
operators are simply comparing the contents of the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>handles</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
If the addresses inside the <A NAME="Index1465"></A><A NAME="Index1466"></A>handles
are the same, the handles are pointing to the same object and are therefore
“equal.” So what the operators are really testing is whether the
handles are aliased to the same object!
</FONT><a name="_Toc375545428"></a><a name="_Toc408018661"></a><P></DIV>
<A NAME="Heading374"></A><H3 ALIGN=LEFT>
The
effect of Object.clone( )
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">What
actually happens when <A NAME="Index1467"></A><A NAME="Index1468"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is called that makes it so essential to call <A NAME="Index1469"></A><A NAME="Index1470"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
when you override
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in your class? The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method in the root class is responsible for creating the correct amount of
storage and making the bitwise copy of the bits from the original object into
the new object’s storage. That is, it doesn’t just make storage and
copy an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
– it actually figures out the size of the precise object that’s
being copied and duplicates that. Since all this is happening from the code in
the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method defined in the root class (that has no idea what’s being inherited
from it), you can guess that the process involves <A NAME="Index1471"></A>RTTI
to determine the actual object that’s being cloned. This way, the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method can create the proper amount of storage and do the correct bitcopy for
that type.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Whatever
you do, the first part of the cloning process should normally be a call to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
This establishes the groundwork for the cloning operation by making an exact
duplicate. At this point you can perform other operations necessary to complete
the cloning.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">To
know for sure what those other operations are, you need to understand exactly
what
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
buys you. In particular, does it automatically clone the destination of all the
handles? The following example tests this:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: Snake.java</font>
<font color="#009900">// Tests cloning to see if destination of</font>
<font color="#009900">// handles are also cloned.</font>
<font color="#0000ff">public</font> <font color="#0000ff">class</font> Snake <font color="#0000ff">implements</font> Cloneable {
<font color="#0000ff">private</font> Snake next;
<font color="#0000ff">private</font> <font color="#0000ff">char</font> c;
<font color="#009900">// Value of i == number of segments</font>
Snake(<font color="#0000ff">int</font> i, <font color="#0000ff">char</font> x) {
c = x;
<font color="#0000ff">if</font>(--i > 0)
next = <font color="#0000ff">new</font> Snake(i, (<font color="#0000ff">char</font>)(x + 1));
}
<font color="#0000ff">void</font> increment() {
c++;
<font color="#0000ff">if</font>(next != <font color="#0000ff">null</font>)
next.increment();
}
<font color="#0000ff">public</font> String toString() {
String s = ":" + c;
<font color="#0000ff">if</font>(next != <font color="#0000ff">null</font>)
s += next.toString();
<font color="#0000ff">return</font> s;
}
<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) {}
<font color="#0000ff">return</font> o;
}
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
Snake s = <font color="#0000ff">new</font> Snake(5, 'a');
System.out.println("s = " + s);
Snake s2 = (Snake)s.clone();
System.out.println("s2 = " + s2);
s.increment();
System.out.println(
"after s.increment, s2 = " + s2);
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">A
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Snake</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is made up of a bunch of segments, each of type
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Snake</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Thus, it’s a singly-linked list. The segments are created recursively,
decrementing the first constructor argument for each segment until zero is
reached. To give each segment a unique tag, the second argument, a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>char</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
is incremented for each recursive constructor call.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>increment( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method recursively increments each tag so you can see the change, and the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>toString( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
recursively prints each tag. The output is:
</FONT><P></DIV>
<font color="#990000"><PRE>s = :a:b:c:d:e
s2 = :a:b:c:d:e
after s.increment, s2 = :a:c:d:e:f </PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
means that only the first segment is duplicated by
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
so it does a <A NAME="Index1472"></A>shallow
copy. If you want the whole snake to be duplicated – a <A NAME="Index1473"></A>deep
copy – you must perform the additional operations inside your overridden
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You’ll
typically call
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in any class derived from a cloneable class to make sure that all of the
base-class operations (including
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
take place. This is followed by an explicit call to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">for
every handle in your object; otherwise those handles will be aliased to those
of the original object. It’s analogous to the way constructors are called
– base-class constructor first, then the next-derived constructor, and so
on to the most-derived constructor. The difference is that
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is not a constructor so there’s nothing to make it happen automatically.
You must make sure to do it yourself.
</FONT><a name="_Toc408018662"></a><P></DIV>
<A NAME="Heading375"></A><H3 ALIGN=LEFT>
Cloning
a composed object
<P><A NAME="Index1474"></A><A NAME="Index1475"></A></H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">There’s
a problem you’ll encounter when trying to deep copy a composed object.
You must assume that the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method in the member objects will in turn perform a deep copy on
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -