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

📄 chapter12.html

📁 java 是一个很好的网络开发环境。由于它是通过解释的方法
💻 HTML
📖 第 1 页 / 共 5 页
字号:
<UL>
<LI><FONT FACE="Symbol">	</FONT><FONT FACE="Georgia">Aliasing happens
automatically during argument
passing.</FONT><LI><FONT FACE="Symbol">	</FONT><FONT FACE="Georgia">There
are no local objects, only local
handles.</FONT><LI><FONT FACE="Symbol">	</FONT><FONT FACE="Georgia">Handles
have scopes, objects do
not.</FONT><LI><FONT FACE="Symbol">	</FONT><FONT FACE="Georgia">Object
lifetime is never an issue in
Java.</FONT><LI><FONT FACE="Symbol">	</FONT><FONT FACE="Georgia">There is
no language support (e.g. const) to prevent objects from being modified (to
prevent negative effects of
aliasing).</FONT></UL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If
you&#8217;re only reading information from an object and not modifying it,
passing a handle is the most efficient form of argument passing. This is nice;
the default way of doing things is also the most efficient. However, sometimes
it&#8217;s necessary to be able to treat the object as if it were
&#8220;local&#8221; so that changes you make affect only a local copy and do not
modify the outside object. Many programming languages support the ability to
automatically make a local copy of the outside object, inside the
method.</FONT><A NAME="fnB46" HREF="#fn46">[46]</A><FONT FACE="Georgia">
Java does not, but it allows you to produce this
effect.</FONT><A NAME="_Toc408018657"></A><BR></P></DIV>
<A NAME="Heading367"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Pass by value</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This brings up the terminology
issue, which always seems good for an argument. The term is
&#8220;<A NAME="Index1446"></A>pass by value,&#8221; and the meaning depends on
how you perceive the operation of the program. The general meaning is that you
get a local copy of whatever you&#8217;re passing, but the real question is how
you think about what you&#8217;re passing. When it comes to the meaning of
&#8220;pass by value,&#8221; there are two fairly distinct
camps:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Georgia">	Java passes everything by value. When
you&#8217;re passing primitives into a method, you get a distinct copy of the
primitive. When you&#8217;re passing a handle into a method, you get a copy of
the handle. Ergo, everything is pass by value. Of course, the assumption is that
you&#8217;re always thinking (and caring) that handles are being passed, but it
seems like the Java design has gone a long way toward allowing you to ignore
(most of the time) that you&#8217;re working with a handle. That is, it seems to
allow you to think of the handle as &#8220;the object,&#8221; since it
implicitly dereferences it whenever you make a method
call.</FONT><LI><FONT FACE="Georgia">	Java passes primitives by value (no
argument there), but objects are passed by reference. This is the world view
that the handle is an alias for the object, so you <I>don&#8217;t</I> think
about passing handles, but instead say &#8220;I&#8217;m passing the
object.&#8221; Since you don&#8217;t get a local copy of the object when you
pass it into a method, objects are clearly not passed by value. There appears to
be some support for this view within Sun, since one of the &#8220;reserved but
not implemented&#8221; keywords is <B>byvalue</B>. (There&#8217;s no knowing,
however, whether that keyword will ever see the light of
day.)</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Having given both
camps a good airing and after saying &#8220;It depends on how you think of a
handle,&#8221; I will attempt to sidestep the issue for the rest of the book. In
the end, it isn&#8217;t <I>that</I> important &#8211; what is important is that
you understand that passing a handle allows the caller&#8217;s object to be
changed
unexpectedly.</FONT><A NAME="_Toc375545425"></A><A NAME="_Toc408018658"></A><BR></P></DIV>
<A NAME="Heading368"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Cloning objects</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The most likely reason for making a
local copy of an object is if you&#8217;re going to modify that object and you
don&#8217;t want to modify the caller&#8217;s object. If you decide that you
want to make a local copy, you simply use the <B>clone(&#160;)</B> method to
perform the operation. This is a method that&#8217;s defined as <B>protected
</B>in the base class <B>Object</B> and which you must override as <B>public
</B>in any derived classes that you want to clone. For example, the standard
library class <B>Vector</B> overrides <B>clone(&#160;)</B>, so we can call
<B>clone(&#160;)</B> for <B>Vector</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Cloning.java</font>
<font color=#009900>// The clone() operation works for only a few</font>
<font color=#009900>// items in the standard Java library.</font>
<font color=#0000ff>import</font> java.util.*;

<font color=#0000ff>class</font> Int {
  <font color=#0000ff>private</font> <font color=#0000ff>int</font> i;
  <font color=#0000ff>public</font> Int(<font color=#0000ff>int</font> ii) { i = ii; }
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> increment() { i++; }
  <font color=#0000ff>public</font> String toString() { 
    <font color=#0000ff>return</font> Integer.toString(i); 
  }
}

<font color=#0000ff>public</font> <font color=#0000ff>class</font> Cloning {
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
    Vector v = <font color=#0000ff>new</font> Vector();
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 10; i++ )
      v.addElement(<font color=#0000ff>new</font> Int(i));
    System.out.println(<font color=#004488>"v: "</font> + v);
    Vector v2 = (Vector)v.clone();
    <font color=#009900>// Increment all v2's elements:</font>
    <font color=#0000ff>for</font>(Enumeration e = v2.elements();
        e.hasMoreElements(); )
      ((Int)e.nextElement()).increment();
    <font color=#009900>// See if it changed v's elements:</font>
    System.out.println(<font color=#004488>"v: "</font> + v);
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>clone(&#160;)</B> method
produces an <B>Object</B>, which must then be recast to the proper type. This
example shows how <B>Vector</B>&#8217;s<B> clone(&#160;)</B> method <I>does
not</I> automatically try to clone each of the objects that the <B>Vector</B>
contains &#8211; the old <B>Vector</B> and the cloned <B>Vector</B> are aliased
to the same objects. This is often called a
<A NAME="Index1447"></A><A NAME="Index1448"></A><I>shallow copy</I>, since
it&#8217;s copying only the &#8220;surface&#8221; portion of an object. The
actual object consists of this &#8220;surface&#8221; plus all the objects that
the handles are pointing to, plus all the objects <I>those </I>objects are
pointing to, etc. This is often referred to as the
&#8220;<A NAME="Index1449"></A><A NAME="Index1450"></A>web of objects.&#8221;
Copying the entire mess is called a
<A NAME="Index1451"></A><A NAME="Index1452"></A><I>deep
copy</I>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see the effect of the
shallow copy in the output, where the actions performed on <B>v2 </B>affect
<B>v</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>v: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
v: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Not trying to <B>clone(&#160;)
</B>the objects contained in the <B>Vector </B>is probably a fair assumption
because there&#8217;s no guarantee that those objects <I>are</I>
cloneable.</FONT><A NAME="fnB47" HREF="#fn47">[47]</A><A NAME="_Toc375545426"></A><A NAME="_Toc408018659"></A><BR></P></DIV>
<A NAME="Heading369"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Adding cloneability to a class</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Even though the clone method is
defined in the base-of-all-classes <B>Object</B>, cloning is <I>not
</I>automatically available in every
class.</FONT><A NAME="fnB48" HREF="#fn48">[48]</A><FONT FACE="Georgia">
This would seem to be counterintuitive to the idea that base-class methods are
always available in derived classes. Cloning in Java goes against this idea; if
you want it to exist for a class, you must specifically add code to make cloning
work.</FONT><BR></P></DIV>
<A NAME="Heading370"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Using a trick with protected</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To prevent default clonability in
every class you create, the
<A NAME="Index1453"></A><A NAME="Index1454"></A><B>clone(&#160;)</B> method is
<B>protected</B> in the base class <B>Object</B>. Not only does this mean that
it&#8217;s not available by default to the client programmer who is simply using
the class (not subclassing it), but it also means that you cannot call
<B>clone(&#160;)</B> via a handle to the base class. (Although that might seem
to be useful in some situations, such as to polymorphically clone a bunch of
<B>Object</B>s.) It is in effect a way to give you, at compile time, the
information that your object is not cloneable &#8211; and oddly enough most
classes in the standard Java library are not cloneable. Thus, if you
say:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>    Integer x = <font color=#0000ff>new</font> Integer(1);
    x = x.clone();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You will get, at compile time, an
error message that says <B>clone(&#160;) </B>is not accessible (since
<B>Integer</B> doesn&#8217;t override it and it defaults to the <B>protected</B>
version). </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If, however, you&#8217;re in a
class derived from <B>Object </B>(as all classes are), then you have permission
to call <B>Object.clone(&#160;) </B>because it&#8217;s
<A NAME="Index1455"></A><B>protected </B>and you&#8217;re an inheritor. The base
class <B>clone(&#160;) </B>has useful functionality &#8211; it performs the
actual bitwise duplication <I>of the derived-class object</I>, thus acting as
the common cloning operation. However, you then need to make <I>your</I> clone
operation <B>public</B> for it to be accessible. So two key issues when you
clone are: virtually always call <A NAME="Index1456"></A><B>super.clone(&#160;)
</B>and make your clone <B>public</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You&#8217;ll probably want to
override <B>clone(&#160;) </B>in any further derived classes, otherwise your
(now <B>public</B>) <B>clone(&#160;)</B> will be used, and that might not do the
right thing (although, since <B>Object.clone(&#160;)</B> makes a copy of the
actual object, it might). The <B>protected</B> trick works only once, the first
time you inherit from a class that has no clonability and you want to make a
class that&#8217;s cloneable. In any classes inherited from your class the
<B>clone(&#160;) </B>method is available since it&#8217;s not possible in Java
to reduce the access of a method during derivation. That is, once a class is
cloneable, everything derived from it is cloneable unless you use provided
mechanisms (described later) to &#8220;turn off&#8221; cloning.</FONT><BR></P></DIV>
<A NAME="Heading371"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Implementing the Cloneable interface</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There&#8217;s one more thing you
need to do to complete the clonability of an object: implement the
<A NAME="Index1457"></A><B>Cloneable</B> <B>interface</B>. This
<A NAME="Index1458"></A><B>interface</B> is a bit strange because it&#8217;s
empty!</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>interface</font> Cloneable {}</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The reason for implementing this
empty <B>interface</B> is obviously not because you are going to upcast to
<B>Cloneable</B> and call one of its methods. The use of <B>interface</B> here
is considered by some to be a &#8220;hack&#8221; because it&#8217;s using a
feature for something other than its original intent. Implementing the
<B>Cloneable</B> <B>interface</B> acts as a kind of a flag, wired into the type
of the class. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are two reasons for the
existence of the <B>Cloneable</B> <B>interface</B>. First, you might have an
upcast handle to a base type and not know whether it&#8217;s possible to clone
that object. In this case, you can use the <B>instanceof</B> keyword (described
in Chapter 11) to find out whether the handle is connected to an object that can
be cloned:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>if</font>(myHandle <font color=#0000ff>instanceof</font> Cloneable) <font color=#009900>// ...</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The second reason is that mixed
into this design for clonability was the thought that maybe you didn&#8217;t
want all types of objects to be cloneable. So <B>Object.clone(&#160;)</B>
verifies that a class implements the <B>Cloneable</B> interface. If not, it
throws a <B>CloneNotSupportedException</B> exception. So in general,
you&#8217;re forced to <B>implement Cloneable</B> as part of support for
cloning.</FONT><A NAME="_Toc375545427"></A><A NAME="_Toc408018660"></A><BR></P></DIV>
<A NAME="Heading372"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Successful cloning</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once you understand the details of
implementing the <B>clone(&#160;)</B> method, you&#8217;re able to create
classes that can be easily duplicated to provide a local copy:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: LocalCopy.java</font>
<font color=#009900>// Creating local copies with clone()</font>
<font color=#0000ff>import</font> java.util.*;

<font color=#0000ff>class</font> MyObject <font color=#0000ff>implements</font> Cloneable {
  <font color=#0000ff>int</font> i;
  MyObject(<font color=#0000ff>int</font> ii) { i = ii; }
  <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();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -