📄 tij0128.html
字号:
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
first class,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Ordinary</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
represents the kinds of classes we’ve seen throughout the book: no
support for cloning, but as it turns out, no prevention of cloning either. But
if you have a handle to an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Ordinary</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object that might have been upcast from a more derived class, you can’t
tell if it can be cloned or not.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>WrongClone</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
shows an incorrect way to implement cloning. It does override
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and makes that method
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
but it doesn’t implement
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
so when
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is called (which results in a call to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">),
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CloneNotSupportedException</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is thrown so the cloning doesn’t work.
</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>IsCloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
you can see all the right actions performed for cloning:
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is overridden and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is implemented. However, this
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method and several others that follow in this example
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>do
not
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
catch
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CloneNotSupportedException,</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
but instead pass it through to the caller, who must then put a try-catch block
around it. In your own
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
methods you will typically catch
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CloneNotSupportedException</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>inside</I></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">
rather than passing it through. As you’ll see, in this example it’s
more informative to pass the exceptions through.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>NoMore</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
attempts to “turn off” cloning in the way that the Java designers
intended: in the derived class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
you throw
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CloneNotSupportedException</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">method
in class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>TryMore</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
properly calls
</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 this resolves to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>NoMore.clone( ),</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
which throws an exception and prevents cloning.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">But
what if the programmer doesn’t follow the “proper” path of
calling <A NAME="Index1485"></A><A NAME="Index1486"></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">
inside the overridden
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method? In
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>BackOn</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
you can see how this can happen. This class uses a separate method
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>duplicate( )
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">to
make a copy of the current object and calls this method inside
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>instead</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
of calling
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
The exception is never thrown and the new class is cloneable. You can’t
rely on throwing an exception to prevent making a cloneable class. The only
sure-fire solution is shown in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>ReallyNoMore</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
which is
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>final</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and thus cannot be inherited. That means if
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
throws an exception in the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>final</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
class, it cannot be modified with inheritance and the prevention of cloning is
assured. (You cannot explicitly 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">from
a class that has an arbitrary level of inheritance; you are limited to calling
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone( ),</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
which has access to only the direct base class.) Thus, if you make any objects
that involve security issues, you’ll want to make those classes
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>final</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">The
first method you see in class
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>CheckCloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>tryToClone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
which takes any
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Ordinary</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object and checks to see whether it’s cloneable with
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>instanceof</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
If so, it casts the object to an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>IsCloneable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
calls
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and casts the result back to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Ordinary</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
catching any exceptions that are thrown. Notice the use of run-time type
identification (see Chapter 11) to print out the class name so you can see
what’s happening.
</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( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
different types of
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Ordinary</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
objects are created and upcast to
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Ordinary</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in the array definition. The first two lines of code after that create a plain
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Ordinary</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object and try to clone it. However, this code will not compile because
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>protected</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
The remainder of the code steps through the array and tries to clone each
object, reporting the success or failure of each. The output is:
</FONT><P></DIV>
<font color="#990000"><PRE>Attempting IsCloneable
Cloned IsCloneable
Attempting NoMore
Could not clone NoMore
Attempting TryMore
Could not clone TryMore
Attempting BackOn
Cloned BackOn
Attempting ReallyNoMore
Could not clone ReallyNoMore </PRE></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">So
to summarize, if you want a class to be cloneable:
</FONT><P></DIV>
<OL>
<LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"> Implement
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><LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"> Override
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT><LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"> Call
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>super.clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
inside your
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT><LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"> Capture
exceptions inside your
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>clone( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT></OL><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
will produce the most convenient effects.
</FONT><a name="_Toc375545432"></a><a name="_Toc408018668"></a><P></DIV>
<A NAME="Heading381"></A><H3 ALIGN=LEFT>
The
copy-constructor
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Cloning
can seem to be a complicated process to set up. It might seem like there should
be an alternative. One approach that might occur to you (especially if
you’re a C++ programmer) is to make a special constructor whose job it is
to duplicate an object. In C++, this is called the <A NAME="Index1487"></A><A NAME="Index1488"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>copy
constructor
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
At first, this seems like the obvious solution. Here’s an example:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: CopyConstructor.java</font>
<font color="#009900">// A constructor for copying an object</font>
<font color="#009900">// of the same type, as an attempt to create</font>
<font color="#009900">// a local copy.</font>
<font color="#0000ff">class</font> FruitQualities {
<font color="#0000ff">private</font> <font color="#0000ff">int</font> weight;
<font color="#0000ff">private</font> <font color="#0000ff">int</font> color;
<font color="#0000ff">private</font> <font color="#0000ff">int</font> firmness;
<font color="#0000ff">private</font> <font color="#0000ff">int</font> ripeness;
<font color="#0000ff">private</font> <font color="#0000ff">int</font> smell;
<font color="#009900">// etc.</font>
FruitQualities() { <font color="#009900">// Default constructor</font>
<font color="#009900">// do something meaningful...</font>
}
<font color="#009900">// Other constructors:</font>
<font color="#009900">// ...</font>
<font color="#009900">// Copy constructor:</font>
FruitQualities(FruitQualities f) {
weight = f.weight;
color = f.color;
firmness = f.firmness;
ripeness = f.ripeness;
smell = f.smell;
<font color="#009900">// etc.</font>
}
}
<font color="#0000ff">class</font> Seed {
<font color="#009900">// Members...</font>
Seed() { <font color="#009900">/* Default constructor */</font> }
Seed(Seed s) { <font color="#009900">/* Copy constructor */</font> }
}
<font color="#0000ff">class</font> Fruit {
<font color="#0000ff">private</font> FruitQualities fq;
<font color="#0000ff">private</font> <font color="#0000ff">int</font> seeds;
<font color="#0000ff">private</font> Seed[] s;
Fruit(FruitQualities q, <font color="#0000ff">int</font> seedCount) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -