⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tij0127.html

📁 学习java的经典书籍
💻 HTML
📖 第 1 页 / 共 5 页
字号:
</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(&#160;)</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&#8217;d expect a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone(&#160;)</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(&#160;)</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&#8217;t, 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone(&#160;)</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&#8217;t clone it. Thus, you&#8217;ve got to surround
your call to 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone(&#160;)</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&#8217;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(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>f(&#160;)</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(&#160;)</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(&#160;)</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(&#160;)</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&#8217;s defined that way in 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone(&#160;)</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(&#160;)</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&#8217;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
&#8220;equal.&#8221; 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(&#160;)
</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(&#160;)</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(&#160;)</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(&#160;)</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(&#160;)</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&#8217;s storage. That is, it doesn&#8217;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">
&#8211; it actually figures out the size of the precise object that&#8217;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(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method defined in the root class (that has no idea what&#8217;s being inherited
from it), you can guess that the process involves <A NAME="Index1471"></A>RTTI
to determine the actual object that&#8217;s being cloned. This way, the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone(&#160;)</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(&#160;)</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(&#160;)</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 &gt; 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&#8217;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(&#160;)</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(&#160;)</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(&#160;)</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 &#8211; a <A NAME="Index1473"></A>deep
copy &#8211; you must perform the additional operations inside your overridden 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone(&#160;)</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&#8217;ll
typically call 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone(&#160;)</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(&#160;)</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(&#160;)
</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&#8217;s analogous to the way constructors are called
&#8211; 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(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is not a constructor so there&#8217;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&#8217;s
a problem you&#8217;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(&#160;)</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 + -