Some time ago, I described a couple of surprising design choices in the JDK functional interfaces API.
Lately, during a lesson, a student of mine proposed to shallow-copy an ArrayList by using the clone() method:
I thought this is another API gotcha worth writing about.
Cloning an object means a new object is created with the same state as the original one.
As per the JavaDoc:
Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object
x, the expression:x.clone() != xwill be
true, and that the expression:x.clone().getClass() == x.getClass()will be
true, but these are not absolute requirements. While it is typically the case that:x.clone().equals(x)will be
true, this is not an absolute requirement.
https://docs.oracle.com/javase/10/docs/api/java/lang/Object.html#clone()
If I were to design Cloneable from scratch, this is what I would probably end up doing:
This way, only classes implementing Cloneable have a clone() method.
I believe this is the standard way to use a type system.
With generics, it could even be improved:
Interestingly enough, the design provided by the JDK is quite different:
Compared to the nominal design:
- The
Cloneableinterface has no method defined - it’s a marker interface. - The
Objectclass provides theclone()method.
A class implements the
Cloneableinterface to indicate to theObject.clone()method that it is legal for that method to make a field-for-field copy of instances of that class.Invoking Object’s clone method on an instance that does not implement the
Cloneableinterface results in the exceptionCloneNotSupportedExceptionbeing thrown.
https://docs.oracle.com/javase/10/docs/api/java/lang/Cloneable.html
With that approach, checks are made at runtime instead of compile time. This is not something to expect from a language with static typing!
Conclusion
Put clone() in a box, lock it, throw away the key and forget it ever existed.
|
The Java API provides two ways to copy a
|