Complex HashMap has different hashCode after serialization
I am parsing a xml file into a complex HashMap looking like this:
Map<String, Map<String, EcmObject>
EcmObject:
public class EcmObject implements Comparable, Serializable {
private final EcmObjectType type;
private final String name;
private final List<EcmField> fields;
private final boolean pages;
// getter, equals, hashCode
}
EcmObjectType:
public enum EcmObjectType implements Serializable {
FOLDER, REGISTER, DOCUMENT
}
EcmField
public class EcmField implements Comparable, Serializable {
private final EcmFieldDataType dataType;
private final EcmFieldControlType controlType;
private final String name;
private final String dbname;
private final String internalname;
private final Integer length;
// getter, equals, hashCode
}
EcmFieldDataType
public enum EcmFieldDataType implements Serializable {
TEXT, DATE, NUMBER, GROUP, DEC;
}
and EcmFieldControlType
public enum EcmFieldControl开发者_如何学JAVAType implements Serializable{
DEFAULT, CHECKBOX, LIST, DBLIST, TEXTAREA, HIERARCHY, TREE, GRID, RADIO, PAGECONTROL, STATIC;
}
I have overwritten all hashCode and equal methods by usind commons lang's EqualsBuilder and HashCodeBuilder. Now when I copy a A HashMap this way:
Map<String, Map<String, EcmObject>> m = EcmUtil.convertXmlObjectDefsToEcmEntries(new File("e:\\objdef.xml"));
Map<String, Map<String, EcmObject>> m2;
System.out.println(m.hashCode());
ByteArrayOutputStream baos = new ByteArrayOutputStream(8 * 4096);
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(m);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
m2 = (Map<String, Map<String, EcmObject>>) ois.readObject();
System.out.println(m.hashCode());
System.out.println(m2.hashCode());
m.hashCode() is not equal to m2.hashCode()
here is my output:
-1639352210
-2071553208
1679930154
Another strange thing is, that eg. 10 times m has the same hashcode and suddenly on the 11th time the hashcode is different...
Any ideas what this is about?
Hashcode of enum
is not consistent across JVM instances. You can use hashcode of enum.toString()
instead.
Since the hashCode
of a HashMap
is defined in terms of the hashCode
of each key and value, I'd try to find out which key or element produces a different hashCode
after serialization.
Ok, as Mr Sauer suggested, I wrote some test code to find out which element has a different hashCode and I found out, that all(!) EcmField-Objects have different hashCodes, but all of EcmField's parameter have got the same hashcode !!
Here are hashcode and equals implementations:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EcmField ecmField = (EcmField) o;
return new EqualsBuilder()
.appendSuper(super.equals(o))
.append(controlType, ecmField.controlType)
.append(dataType, ecmField.dataType)
.append(dbname, ecmField.dbname)
.append(internalname, ecmField.internalname)
.append(length, ecmField.length)
.append(name, ecmField.name)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(13, 37)
.append(controlType)
.append(dataType)
.append(dbname)
.append(internalname)
.append(length)
.append(name)
.hashCode();
}
and this is my test code
EcmField ecmFieldOne = ecmFieldsOne.get(i);
EcmField ecmFieldTwo = ecmFieldsTwo.get(i);
if (ecmFieldOne.hashCode() != ecmFieldTwo.hashCode()) {
if (!ecmFieldOne.equals(ecmFieldsTwo)) {
System.out.println("Field: " + ecmFieldOne.getName() + " != " + ecmFieldTwo.getName());
}
if (ecmFieldOne.getControlType().hashCode() != ecmFieldTwo.getControlType().hashCode()) {
System.out.println("ControlType: " + ecmFieldOne.getControlType() + " != " + ecmFieldTwo.getControlType());
}
if (ecmFieldOne.getDataType().hashCode() != ecmFieldTwo.getDataType().hashCode()) {
System.out.println("DataType: " + ecmFieldOne.getDataType() + " != " + ecmFieldTwo.getDataType());
}
if (ecmFieldOne.getDbname().hashCode() != ecmFieldTwo.getDbname().hashCode()) {
System.out.println("Dbname: " + ecmFieldOne.getDbname() + " != " + ecmFieldTwo.getDbname());
}
if (ecmFieldOne.getInternalname().hashCode() != ecmFieldTwo.getInternalname().hashCode()) {
System.out.println("Internalname: " + ecmFieldOne.getInternalname() + " != " + ecmFieldTwo.getInternalname());
}
if (ecmFieldOne.getLength().hashCode() != ecmFieldTwo.getLength().hashCode()) {
System.out.println("Length: " + ecmFieldOne.getLength() + " != " + ecmFieldTwo.getLength());
}
if (ecmFieldOne.getName().hashCode() != ecmFieldTwo.getName().hashCode()) {
System.out.println("Name: " + ecmFieldOne.getName() + " != " + ecmFieldTwo.getName());
}
}
And only the first two if clauses are entered (if (ecmFieldOne.hashCode() != ecmFieldTwo.hashCode())
and if (!ecmFieldOne.equals(ecmFieldsTwo))
), all others are false
I don't get it...
精彩评论