At first it seems a No Brainer Problem
If you assign the same pre-initialized instance of the same class to two variables, do they always equal to each other? Note that this is the typical pre-jdk1.5 typesafe enum pattern.
public class ReagentType implements Serializable{Sounds like a no brainer. The answer obviously should be yes. checkEquals() method will print out "true". Always. That is, in an ideal world.
private static final String PROTEIN_TYPE = "PROTEIN";
// more types here
public ReagentType PROTEIN = new ReagentType(PROTEIN_TYPE);
// more pre-initialized instance here
private String type;
public String getType(){
return this.type;
}
private ReagentType(String type){
this.type = type;
}
public void checkEquals(ReagentType a, ReagentType b){
System.out.println(a.equals(b));
}
public static void main(String[] args){
ReagentType a = ReagentType.PROTEIN;
ReagentType b = ReagentType.PROTEIN;
checkEquals(a,b);
}
}
However...
In real world, assuming a & b are both assigned to ReagentType.PROTEIN, in many cases we will see checkEquals() method prints out "false". The standard java equals() compares object identity, which is nothing but the memory location of the object instance, which will most certainly fail in a real world deployment environment.
- Consider Distributed Computing. Either a or b has travelled the wire before checkEquals() method gets it, a.equals(b) is false. They resides in two different memory location.
- Even in a single server, after serializable/deserialization, it's guranteed that an object will have a different memory location. a equals() the serialize/deserialized copy of itself, is false.
- Consider an EJB invoking a method in another EJB, if they're packaged in different deployment JARs and both contains the ReagentType class, depends how the class loading mechanism in app-server works, there might exists many pre-initialized instance of the REAGENT object and they have different memory location.
Oh yeah, there's always solutions. For one, implement the equals() method properly.
public boolean equals(Object obj){For two, for those who're not big fan of the typesafe enum pattern, they can simply fall back to the good old set-of-static-primitive-values enumeration.
if (obj!=null && obj instanceof ReagentType){
return getType().equals( ((ReagentType)obj).getType());
} else {
return false;
}
}
// hashcode() methods omitted here
A note is that while implementation of the RMI readResolve() method might seem to solve this problem, it actually will fail in scenario 3, since the container may decide not to perform serialize/deserialize if the EJBs resides in the same server. However the readResolve() solution should be safe in non-EJB situation where the class loading situation is simpler.
1 comment:
Great and Useful Article.
Online Java Training
Online Java Training from India
Online Java Training
Online Java Training From India
Java Training Institutes in Chennai
Java Training in Chennai
Post a Comment