|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 4 of 5
==).null or semantically equivalent (as reported by equals()).
For a bit more help on deciding how you should define equals(), consider that any implementation of equals() should have the following properties:
a, a.equals(null) should return false.a, a.equals(a) should return true. (equals() is reflexive.)a and b, a.equals(b) should return true if and only if b.equals(a) returns true. (equals() is symmetric.)a, b, and c, if a.equals(b) returns true and b.equals(c) returns true, then a.equals(c) should return true. (equals() is transitive.)a and b, multiple invocations of a.equals(b) consistently return true or consistently return false. (equals() is consistent.)
If you wish to disallow cloning of an object, you can simply choose not to implement Cloneable, unless a superclass already implements Cloneable. In that case, you'll need to override clone() and throw CloneNotSupportedException. If a superclass implementation of clone() has removed CloneNotSupportedException from its throws clause, you should either change that superclass or allow cloning in the subclass.
If you wish to disallow serialization, you can simply choose not to implement Serializable.
Note that defining finalize() is not part of this idiom. A finalizer is not appropriate in general cases, although under certain circumstances you may
want to write a finalizer. For advice on writing finalizers, follow the link from the Resources section to a previous Design Techniques article on that subject.
Note also that defining toString() is missing from the list above. I left it out because I believe Object has a reasonable default implementation for this method. Object's toString() method returns a string composed of the name of the class, an "at" sign ("@"), and the unsigned hexadecimal representation
of the hash code of the object. If you do override toString, you should return a string that "textually represents" the object. The returned result should be concise, informative, and
easy to read.
One other thing missing from the canonical object idiom is a no-arg constructor. Any class that has a no-arg constructor and
implements Serializable is a JavaBean. See the Resources section for a link to a discussion of when it is appropriate to make a class into a bean.
To help spark some discussion on the Flexible Java Forum, a discussion forum devoted to Java design topics, I will throw out some of the issues that may present themselves with this idiom (see the Resources section for a link to the forum):
toString from my canonical object recipe?InternalError from the catch clause that catches CloneNotSupportedException? My general advice (given in my "Designing with Exceptions" article) is that programs should throw only exceptions, never errors. Usually the VM throws the errors. But in this case,
I have implemented Cloneable. Thus, if Object's clone() implementation throws CloneNotSupported, I think that may qualify as an internal error to me. Since this "internal error" will likely never happen, what I throw
probably isunimportant. But I'd still feel better about throwing an exception rather than an error. Perhaps what we need is
a java.lang.ThisWasntSupposedToEverHappenException.CloneNotSupportedException at all, because, as I described above, it does tie the hands of anyone wishing to disallow cloning in a subclass.In next month's Design Techniques I'll talk about composition, inheritance, and interfaces.