Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
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
This idiom's canonical form, shown below, uses the == operator to compare values:
public final class NumberConstants{
public static final NumberConstants ONE=new NumberConstants();
public static final NumberConstants TWO=new NumberConstants();
public static final NumberConstants THREE=new NumberConstants();
private NumberConstants(){}
}
void test(NumberConstant num){
//No need to check that the value is on range
if(num==NumberConstant.ONE){
//take some action
}
}
Using the idiom this way works well until you need to make the class serializable. Vladimir Roubtsov discusses the problem with serialization and offers an elegant solution in "Java Tip 122: Beware of Java Typesafe Enumerations."
Roubtsov's solution uses the readResolve() method to return the correct object reference for the constant that matches the local version. That means you can continue
using the convenient == operator even after one of the constants has been deserialized. This approach's only downside is that you must dirty your
hands and implement readResolve() every time you need to write a new class of constants—or do you?
I'm a big fan of reusable code and created an alternate, simple solution. My approach handles the serialization problems for
simple persistence and works in many distributed systems without the need to implement readResolve() in every new class of constants. The solution presented here uses an abstract class you extend as follows:
public final class NumberConstants extends AbstractConstant{
public static final NumberConstants ONE=new NumberConstants();
//etc
private NumberConstants(){}
}
The AbstractConstant class is declared (as its name suggests) abstract so it cannot be instantiated. It also implements Serializable.
The class declares two private methods writeObject() and readObject(). As usual, if these two methods are present in a Serializable class, then they will automatically invoke when the object is serialized/deserialized.
The AbstractConstant class identifies which field of the subclass is being serialized and then writes that field's name into the stream to guarantee
uniqueness—since you can't have duplicate field names in a Java class. However, duplicate field names are possible within
a class hierarchy; so, for this technique to work, subclasses of the AbstractConstant class must be declared final—a rule that should be applied to all typesafe constants. Here's the code for the AbstractConstant class starting with the class definition and the writeObject()method, which writes the field name of the constant being serialized into the ObjectOutputStream:
import java.lang.reflect.Field;
public abstract class AbstractConstant
implements java.io.Serializable{
private transient String _fieldName;
private void writeObject(java.io.ObjectOutputStream out)
throws java.io.IOException {
Class clazz=getClass();
Field [] f=clazz.getDeclaredFields();
for(int i=0;I<f.length;i++){
try{
int mod=f[i].getModifiers();
if(Modifier.isStatic(mod) && Modifier.isFinal(mod)
&& Modifier.isPublic(mod)){
if(this==f[i].get(null)){
String fName=f[i].getName();
out.writeObject(fName);
}
}
}catch(IllegalAccessException ex){
throw new java.io.IOException(ex.getMessage());
}
}
}
The readObject() method then reads back the field name from the stream and assigns it to _fieldName, which is later used in the readResolve() method. The readResolve() method invokes after readObject() when an object is deserialized: