📄 tij0127.html
字号:
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><P></DIV>
<A NAME="Heading371"></A><H4 ALIGN=LEFT>
Using
a trick with protected
</H4>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">To
prevent default clonability in every class you create, the <A NAME="Index1454"></A><A NAME="Index1455"></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 is
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>protected</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in the base class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
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
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
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
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">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><P></DIV>
<font color="#990000"><PRE> Integer x = <font color="#0000ff">new</font> Integer(1);
x = x.clone(); </PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You
will get, at compile time, an error message that says
</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 accessible (since
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Integer</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
doesn’t override it and it defaults to the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>protected</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
version).
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">If,
however, you’re in a class derived from
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">(as
all classes are), then you have permission to call
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">because
it’s <A NAME="Index1456"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>protected
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">and
you’re an inheritor. The base class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">has
useful functionality – it performs the actual bitwise duplication
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>of
the derived-class object
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
thus acting as the common cloning operation. However, you then need to make
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>your</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
clone operation
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
for it to be accessible. So two key issues when you clone are: virtually always
call <A NAME="Index1457"></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">and
make your clone
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</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
probably want to 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
any further derived classes, otherwise your (now
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
will be used, and that might not do the right thing (although, since
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
makes a copy of the actual object, it might). The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>protected</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
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
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">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><P></DIV>
<A NAME="Heading372"></A><H4 ALIGN=LEFT>
Implementing
the Cloneable interface
</H4>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">There’s
one more thing you need to do to complete the clonability of an object:
implement the <A NAME="Index1458"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
This <A NAME="Index1459"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is a bit strange because it’s empty!
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">interface
Cloneable {}
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
reason for implementing this empty
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is obviously not because you are going to upcast to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and call one of its methods. The use of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
here is considered by some to be a “hack” because it’s using
a feature for something other than its original intent. Implementing the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
acts as a kind of a flag, wired into the type of the class.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">There
are two reasons for the existence of the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
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
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>instanceof</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
keyword (described in Chapter 11) to find out whether the handle is connected
to an object that can be cloned:
</FONT><P></DIV><DIV ALIGN=LEFT><TT><FONT FACE="Courier New" SIZE=3 COLOR="Black">if(myHandle
instanceof Cloneable) // ...
</FONT></TT><P></DIV><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">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
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
verifies that a class 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 not, it throws a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CloneNotSupportedException</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
exception. So in general, you’re forced to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>implement
Cloneable
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
as part of support for cloning.
</FONT><a name="_Toc375545427"></a><a name="_Toc408018660"></a><P></DIV>
<A NAME="Heading373"></A><H3 ALIGN=LEFT>
Successful
cloning
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Once
you understand the details of implementing 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, you’re able to create classes that can be easily duplicated to
provide a local copy:
</FONT><P></DIV>
<font color="#990000"><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();
} <font color="#0000ff">catch</font> (CloneNotSupportedException e) {
System.out.println("MyObject can't clone");
}
<font color="#0000ff">return</font> o;
}
<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> LocalCopy {
<font color="#0000ff">static</font> MyObject g(MyObject v) {
<font color="#009900">// Passing a handle, modifies outside object:</font>
v.i++;
<font color="#0000ff">return</font> v;
}
<font color="#0000ff">static</font> MyObject f(MyObject v) {
v = (MyObject)v.clone(); <font color="#009900">// Local copy</font>
v.i++;
<font color="#0000ff">return</font> v;
}
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
MyObject a = <font color="#0000ff">new</font> MyObject(11);
MyObject b = g(a);
<font color="#009900">// Testing handle equivalence,</font>
<font color="#009900">// not object equivalence:</font>
<font color="#0000ff">if</font>(a == b)
System.out.println("a == b");
<font color="#0000ff">else</font>
System.out.println("a != b");
System.out.println("a = " + a);
System.out.println("b = " + b);
MyObject c = <font color="#0000ff">new</font> MyObject(47);
MyObject d = f(c);
<font color="#0000ff">if</font>(c == d)
System.out.println("c == d");
<font color="#0000ff">else</font>
System.out.println("c != d");
System.out.println("c = " + c);
System.out.println("d = " + d);
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">First
of all,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
must be accessible so you must make it
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Second, for the initial part of your
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
operation you should call the base-class version of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
that’s being called here is the one that’s predefined inside
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and you can call it because it’s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -