📄 chapter12.html
字号:
<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’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’s necessary to be able to treat the object as if it were
“local” 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
“<A NAME="Index1446"></A>pass by value,” 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’re passing, but the real question is how
you think about what you’re passing. When it comes to the meaning of
“pass by value,” there are two fairly distinct
camps:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Georgia"> Java passes everything by value. When
you’re passing primitives into a method, you get a distinct copy of the
primitive. When you’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’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’re working with a handle. That is, it seems to
allow you to think of the handle as “the object,” 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’t</I> think
about passing handles, but instead say “I’m passing the
object.” Since you don’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 “reserved but
not implemented” keywords is <B>byvalue</B>. (There’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 “It depends on how you think of a
handle,” I will attempt to sidestep the issue for the rest of the book. In
the end, it isn’t <I>that</I> important – what is important is that
you understand that passing a handle allows the caller’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’re going to modify that object and you
don’t want to modify the caller’s object. If you decide that you
want to make a local copy, you simply use the <B>clone( )</B> method to
perform the operation. This is a method that’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( )</B>, so we can call
<B>clone( )</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 < 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( )</B> method
produces an <B>Object</B>, which must then be recast to the proper type. This
example shows how <B>Vector</B>’s<B> clone( )</B> method <I>does
not</I> automatically try to clone each of the objects that the <B>Vector</B>
contains – 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’s copying only the “surface” portion of an object. The
actual object consists of this “surface” 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
“<A NAME="Index1449"></A><A NAME="Index1450"></A>web of objects.”
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( )
</B>the objects contained in the <B>Vector </B>is probably a fair assumption
because there’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( )</B> method is
<B>protected</B> in the base class <B>Object</B>. Not only does this mean that
it’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( )</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 – 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( ) </B>is not accessible (since
<B>Integer</B> doesn’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’re in a
class derived from <B>Object </B>(as all classes are), then you have permission
to call <B>Object.clone( ) </B>because it’s
<A NAME="Index1455"></A><B>protected </B>and you’re an inheritor. The base
class <B>clone( ) </B>has useful functionality – 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( )
</B>and make your clone <B>public</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You’ll probably want to
override <B>clone( ) </B>in any further derived classes, otherwise your
(now <B>public</B>) <B>clone( )</B> will be used, and that might not do the
right thing (although, since <B>Object.clone( )</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’s cloneable. In any classes inherited from your class the
<B>clone( ) </B>method is available since it’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 “turn off” 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’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’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 “hack” because it’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’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’t
want all types of objects to be cloneable. So <B>Object.clone( )</B>
verifies that a class implements the <B>Cloneable</B> interface. If not, it
throws a <B>CloneNotSupportedException</B> exception. So in general,
you’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( )</B> method, you’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 + -