📄 tij319.htm
字号:
<li>Object lifetime is never an issue in Java.</li>
<li>There is no language support (e.g., “const”) to prevent objects
from being modified and stop the negative effects of aliasing. You can’t
simply use the <b>final </b>keyword in the argument list; that simply prevents
you from rebinding the reference to a different
object.</li></ul><p>If you’re only reading information from an object and not modifying it, passing a reference 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.<sup><a name="fnB116" href="#fn116">[116]</a></sup> Java does not, but it allows you to produce this effect. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2708" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc24775992"></a><a name="Heading24594"></a>Pass by value</h3>
<p>This brings up the terminology issue, which always seems good for an argument. The term is “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 size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0099" title="Send BackTalk Comment">Feedback</a></font><br></p>
<ol>
<li><a name="Index2153"></a>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 reference into a method, you get a copy of the reference.
Ergo, everything is pass by value. Of course, the assumption is that
you’re always thinking (and caring) that references 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 reference. That is, it seems
to allow you to think of the reference as “the object,” since it
implicitly dereferences it whenever you make a method call. <font size="-2"><a
href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2709" title="Send BackTalk
Comment">Feedback</a></font></li>
<li>Java passes primitives by value (no argument there), but objects are passed
by reference. This is the world view that the reference is an alias for the
object, so you <i>don’t</i> think about passing references, 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 at one time, one of the “reserved but not implemented”
keywords was <b>byvalue</b> (This will probably never be implemented). <font
size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2710"
title="Send BackTalk
Comment">Feedback</a></font></li></ol><p>Having given both camps a good airing, and after saying “It depends on how you think of a reference,” I will attempt to sidestep the issue. In the end, it isn’t <i>that</i> important—what is important is that you understand that passing a reference allows the caller’s object to be changed unexpectedly. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2711" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc375545425"></a><a name="_Toc24775993"></a><a name="Heading24599"></a>Cloning
objects</h3>
<p>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, one approach is to 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 that you must override as <b>public </b>in any derived classes that you want to clone. For example, the standard library class <b>ArrayList</b> overrides <b>clone( )</b>, so we can call <b>clone( )</b> for <b>ArrayList</b>: <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0100" title="Send BackTalk Comment">Feedback</a></font><br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: appendixa: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> com.bruceeckel.simpletest.*;
<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>private</font> <font color=#0000ff>static</font> Test monitor = <font color=#0000ff>new</font> Test();
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
ArrayList v = <font color=#0000ff>new</font> ArrayList();
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < 10; i++ )
v.add(<font color=#0000ff>new</font> Int(i));
System.out.println(<font color=#004488>"v: "</font> + v);
ArrayList v2 = (ArrayList)v.clone();
<font color=#009900>// Increment all v2's elements:</font>
<font color=#0000ff>for</font>(Iterator e = v2.iterator();
e.hasNext(); )
((Int)e.next()).increment();
<font color=#009900>// See if it changed v's elements:</font>
System.out.println(<font color=#004488>"v: "</font> + v);
monitor.expect(<font color=#0000ff>new</font> String[] {
<font color=#004488>"v: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"</font>,
<font color=#004488>"v: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"</font>
});
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><p><br></p>
<p>The <b>clone( )</b> method produces an <b>Object</b>, which must then be recast to the proper type. This example shows how <b>ArrayList</b>’s<b> clone( )</b> method <i>does not</i> automatically try to clone each of the objects that the <b>ArrayList</b> contains—the old <b>ArrayList</b> and the cloned <b>ArrayList</b> are aliased to the same objects. This is often called a <a name="Index2154"></a><a name="Index2155"></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 references are pointing to, plus all the objects <i>those </i>objects are pointing to, etc. This is often referred to as the “web of objects.” Copying the entire mess is called a <a name="Index2156"></a><a name="Index2157"></a><a name="Index2158"></a><a name="Index2159"></a><i>deep copy. </i><font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2712" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>You can see the effect of the shallow copy in the output, where the actions performed on <b>v2 </b>affect <b>v</b>:<br></p>
<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><p><br></p>
<p>Not trying to <b>clone( ) </b>the objects contained in the <b>ArrayList </b>is probably a fair assumption, because there’s no guarantee that those objects <i>are</i> cloneable.<sup><a name="fnB117" href="#fn117">[117]</a></sup> <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2713" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc375545426"></a><a name="_Toc24775994"></a><a name="Heading24642"></a>Adding
cloneability to a class</h3>
<p>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.<sup><a name="fnB118" href="#fn118">[118]</a></sup> This would seem to be counterintuitive to the idea that base-class methods are always available in derived classes. Cloning in Java does indeed go against this idea; if you want it to exist for a class, you must specifically add code to make cloning work. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2714" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h4>
<a name="Heading24653"></a>Using a trick with <b>protected</b></h4>
<p>To prevent default cloneability in every class you create, the <a name="Index2160"></a><a name="Index2161"></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 reference 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:<br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE> Integer x = <font color=#0000ff>new</font> Integer(1);
x = x.clone();</PRE></FONT></BLOCKQUOTE><p><br></p>
<p>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 size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2715" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>If, however, you’re in a method of a class <i>derived</i> from <b>Object </b>(as all classes are), then you have permission to call <b>Object.clone( ) </b>because it’s <a name="Index2162"></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: <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2716" title="Send BackTalk Comment">Feedback</a></font><br></p>
<ul>
<li><a name="Index2163"></a>Call <b>super.clone( ) </b></li>
<li>Make your clone
<b>public</b></li></ul><p>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 cloneability 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 size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2717" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h4>
<a name="Heading24663"></a>Implementing the <b>Cloneable</b> interface</h4>
<p>There’s one more thing you need to do to complete the cloneability of an object: implement the <a name="Index2164"></a><b>Cloneable</b> <b>interface</b>. This <a name="Index2165"></a><b>interface</b> is a bit strange, because it’s empty!<br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>interface</font> Cloneable {}</PRE></FONT></BLOCKQUOTE><p><br></p>
<p>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> in this way is called a <i>tagging interface</i> because it acts as a kind of flag, wired into the type of the class. <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2718" title="Send BackTalk Comment">Feedback</a></font><br></p>
<p>There are two reasons for the existence of the <b>Cloneable</b> <b>interface</b>. First, you might have an upcast reference 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 10) to find out whether the reference is connected to an object that can be cloned: <font size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]A0101" title="Send BackTalk Comment">Feedback</a></font><br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>if</font>(myReference <font color=#0000ff>instanceof</font> Cloneable) <font color=#009900>// ...</font></PRE></FONT></BLOCKQUOTE><p><br></p>
<p>The second reason is that mixed into this design for cloneability 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 size="-2"><a href="mailto:TIJ3@MindView.net?Subject=[TIJ3]AppendA_2719" title="Send BackTalk Comment">Feedback</a></font><br></p>
<h3>
<a name="_Toc375545427"></a><a name="_Toc24775995"></a><a name="Heading24672"></a>Successful
cloning</h3>
<p>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:<br></p>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: appendixa:LocalCopy.java</font>
<font color=#009900>// Creating local copies with clone().</font>
<font color=#0000ff>import</font> com.bruceeckel.simpletest.*;
<font color=#0000ff>import</font> java.util.*;
<font color=#0000ff>class</font> MyObject <font color=#0000ff>implements</font> Cloneable {
<font color=#0000ff>private</font> <font color=#0000ff>int</font> n;
<font color=#0000ff>public</font> MyObject(<font color=#0000ff>int</font> n) { <font color=#0000ff>this</font>.n = n; }
<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) {
System.err.println(<font color=#004488>"MyObject can't clone"</font>);
}
<font color=#0000ff>return</font> o;
}
<font color=#0000ff>public</font> <font color=#0000ff>int</font> getValue() { <font color=#0000ff>return</font> n; }
<font color=#0000ff>public</font> <font color=#0000ff>void</font> setValue(<font color=#0000ff>int</font> n) { <font color=#0000ff>this</font>.n = n; }
<font color=#0000ff>public</font> <font color=#0000ff>void</font> increment() { n++; }
<font color=#0000ff>public</font> String toString() { <font color=#0000ff>return</font> Integer.toString(n); }
}
<font color=#0000ff>public</font> <font color=#0000ff>class</font> LocalCopy {
<font color=#0000ff>private</font> <font color=#0000ff>static</font> Test monitor = <font color=#0000ff>new</font> Test();
<font color=#0000ff>public</font> <font color=#0000ff>static</font> MyObject g(MyObject v) {
<font color=#009900>// Passing a reference, modifies outside object:</font>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -