To eliminate cloning, you might think that you simply set the Clone () method to private (private), but it doesn't work because you can't take a basic class method and make it more "private" in a derived class. So it's not that simple. In addition, it is necessary to control whether an object can be cloned. For a class we design, there are actually a number of scenarios that can be taken:
(1) remain neutral and do nothing for cloning. That is, although it is not true to clone our class, a class inherited from it can determine the clone based on the actual situation. You can make this decision only if Object.clone () has some reasonable action to make on the fields in the class.
(2) Support Clone (), adopt the standard operation of realizing cloneable (clone) ability, and overwrite clone (). In the overridden clone (), you can invoke Super.clone () and catch all violations (so that clone () does not "throw" any violations).
(3) Conditionally support cloning. If the class holds the handle of other objects, and those objects may be able to clone (a collection class is an example), try cloning all the objects that have their handles, and if they "throw" the offending, just let them pass. For example, suppose there is a special vector that tries to clone all the objects it holds. When you write such a vector, you don't know what kind of object the client programmer will put into the vector, so they don't know if they can actually clone it.
(4) Do not implement cloneable (), but overwrite clone () with protected so that any field has the correct replication behavior. As a result, everything inherited from this class can overwrite clone () and Invoke Super.clone () to produce the correct replication behavior. Note that in our implementation, you can and should call Super.clone ()-even if that method would have expected a Cloneable object (or else it would throw an offending) because no one would call it directly on an object of our type. It is invoked only through a derived class, and for that derived class it is necessary to implement cloneable if it is to be guaranteed to work properly.
(5) Do not implement cloneable to try to prevent cloning, and overwrite clone (), to create a violation. For this to happen successfully, only the Suepr.clone () in the redefined clone () is invoked for any class derived from it.
(6) Set the class to final, thereby preventing cloning. If Clone () is not yet covered by any of our superior classes, this scenario will not succeed. If overridden, then overwrites it again and "throws" a clonenotsupportedexception (clone not supported) violation. For a guaranteed clone to be banned, the option of setting the class to final is the only way. In addition, all builders should be private and provide one or more special methods to create objects once they are involved in a confidential object or if you encounter other situations where you want to control the number of objects created. In this way, these methods can limit the number of objects created and their creation conditions-a special case is the singleton (only child) scenario that is introduced in chapter 16th.
The following example summarizes the various implementations of cloning and then "closes" it in a hierarchy:
: Checkcloneable.java//Checking to-if a handle can is cloned//can ' t clone this because it doesn ' t//Override
Clone (): Class Ordinary {}//Overrides clone, but doesn ' t implement/Cloneable:class Wrongclone extends Ordinary { Public Object Clone () throws Clonenotsupportedexception {return super.clone ();//Throws Exception}}//Do Es all the right things for Cloning:class Iscloneable extends ordinary implements cloneable {public Object clone (
) throws Clonenotsupportedexception {return super.clone (); }//Turn off cloning by throwing the Exception:class NoMore extends iscloneable {public Object clone () thro
WS clonenotsupportedexception {throw new clonenotsupportedexception (); } class Trymore extends NoMore {public Object clone () throws Clonenotsupportedexception {//Calls NoMore
. Clone (), throws Exception:return Super.clone (); } class Backon extends NoMore {private Backon duplicate(Backon b) {//Somehow make a copy of B//and return to that copy.
This is a dummy//copy, just to make the Point:return new Backon ();
Public Object Clone () {//doesn ' t call Nomore.clone (): Return duplicate (this); }//Can ' t inherit from-so Can ' t override//The clone is like in Backon:final class Reallynomore extends No More {} public class Checkcloneable {static ordinary Trytoclone (ordinary ord) {String id = ord.getclass (). GetName
();
ordinary x = null;
if (ord instanceof cloneable) {try {System.out.println ("attempting" + ID);
x = (ordinary) ((iscloneable) ORD). Clone ();
SYSTEM.OUT.PRINTLN ("cloned" + ID);
catch (Clonenotsupportedexception e) {System.out.println ("could not clone" + ID);
} return x; public static void Main (string[] args) {//upcasting:ordinary[] ord = {new Iscloneable (), New Wrongclone (), New NoMore(), New Trymore (), New Backon (), New Reallynomore (),};
Ordinary x = new Ordinary (); This won ' t compile, since clone () was//protected in Object://!
x = (ordinary) x.clone ();
Trytoclone () Checks a class implements cloneable:for (int i = 0; i < ord.length; i++)
Trytoclone (Ord[i]); }
} ///:~
The first class ordinary represents the most common class in this book: it does not support cloning, but it does not prohibit cloning it after it is formally applied. But if there is a handle to a ordinary object, and that object may be traced from a deeper derivative, it cannot be judged whether it can be cloned or not.
The Wrongclone class reveals an incorrect way to implement cloning. It does cover object.clone () and sets that method public, but does not implement cloneable. So once an invocation of Super.clone () (due to an invocation of Object.clone ()) is made, a clonenotsupportedexception violation is thrown mercilessly.
In iscloneable, what you see is the correct action for cloning: first overwrite clone (), and realize cloneable. However, this clone () method and several other methods in this example do not capture the clonenotsupportedexception violation, but let it pass and pass to the caller. Subsequently, the caller must surround it with a try-catch code block. In our own clone () method, it is usually necessary to capture the clonenotsupportedexception violation inside the clone () instead of letting it pass. As you will understand later on, for this example, it is the right thing to do.
Class NoMore tried to "turn off" cloning as the Java designer intended: in a derived class clone (), we threw a clonenotsupportedexception violation. The Clone () method in the Trymore class correctly invokes Super.clone () and resolves to nomore.clone (), which throws an violation and prohibits cloning.
But in the already overridden clone () method, what happens if the programmer does not follow the "correct" method of invoking Super.clone ()? In the Backon, you can see what actually happens. This class uses a separate method duplicate () to make a copy of the current object and call the method inside the clone () instead of calling Super.clone (). The violation will never occur, and the new class can be cloned. Therefore, we cannot rely on the "throw" of an illegal method to prevent the production of a class that can be cloned. The only secure method is demonstrated in Reallynomore, which is final and therefore not inheritable. This means that if clone () throws an violation in the final class, it cannot be modified by inheritance, and can effectively prohibit cloning (object.clone () cannot be explicitly invoked from a class that has arbitrary inheritance series; only Super.clone () can be invoked. It can only access the direct base class). Therefore, it is best to make those classes final as long as you are making some objects that involve security issues.
In class Checkcloneable, the first class we see is Trytoclone (), which can accept any ordinary object and use instanceof to check whether it can be cloned. If the answer is yes, the object styling becomes a iscloneable, invokes clone (), and returns the result modeling back to ordinary, and finally captures any violations that may arise. Please note that the class name is printed using the Run-time type identification (see chap. 11th) to make yourself see what happens.
In main (), we created different types of ordinary objects and traced the shape to the ordinary in the array definition. After that, the first two lines of code create a pure ordinary object and attempt to clone it. However, the code is not compiled because clone () is a protected (protected) method in object. The remainder of the code traverses the array and tries to clone each object, reporting their successes or failures, respectively. The output is as follows:
Attempting iscloneable
cloned iscloneable
attempting nomore could not
clone NoMore
attempting
could not clone Trymore
Attempting Backon
cloned Backon attempting reallynomore could not
clone Reallynomore
In short, if you want a class to be able to clone, then:
(1) Implement Cloneable interface
(2) Overwrite clone ()
(3) Call Super.clone () in its own clone ()
(4) Capturing the offending in its own clone ()
This series of steps can achieve the most desirable results.