复杂的HashMap在序列化后具有不同的hashCode

时间:2010-03-19 11:16:20

标签: java hashmap hashcode

我正在将xml文件解析为复杂的HashMap,如下所示:

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;
}

和EcmFieldControlType

public enum EcmFieldControlType implements Serializable{
    DEFAULT, CHECKBOX, LIST, DBLIST, TEXTAREA, HIERARCHY, TREE, GRID, RADIO, PAGECONTROL, STATIC;
}

我已经用usind commons lang的EqualsBuilder和HashCodeBuilder覆盖了所有hashCode和相同的方法。现在,当我以这种方式复制A HashMap时:

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()不等于到m2.hashCode()

这是我的输出:

-1639352210
-2071553208
1679930154

另一个奇怪的是,例如。 10次​​m具有相同的哈希码,并且第11次哈希码突然不同......

任何想法是什么意思?

3 个答案:

答案 0 :(得分:2)

enum的Hashcode在JVM实例中不一致。您可以使用enum.toString()的哈希码代替。

答案 1 :(得分:1)

由于hashCode的{​​{1}}是根据每个键和值的HashMap定义的,我会尝试找出哪个键或元素在序列化后生成不同的hashCode

答案 2 :(得分:0)

好的,正如Sauer先生建议的那样,我写了一些测试代码,找出哪个元素有不同的hashCode,我发现,所有(!)EcmField-Objects都有不同的hashCodes,但是全部EcmField的参数有相同哈希码!!

这是hashcode和equals实现:

@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();
}

这是我的测试代码

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());
    }
}

只输入前两个if子句(if (ecmFieldOne.hashCode() != ecmFieldTwo.hashCode())if (!ecmFieldOne.equals(ecmFieldsTwo))),其他所有子句都是假的

我不明白......