开发者

java :Can I observe value change on object by watching hashcode?

I have a Model class DOModel :

package amarsoft.dbmp.credit.web.model;

import ejp.annotations.ConcreteTableInheritance;
import amarsoft.rcp.base.databinding.BindableModel;

@ConcreteTableInheritance
public class DOModel extends BindableModel {
    /**
     * 编号
     */
    private String id;
    /**
     * 名称
     */
    private String name;
    /**
     * 模板类型,没有太大意义
     */
    private String type;
    /**
     * 模板参数
     */
    private String args;

    private String updateTable;

    private String updateWhere;

    private String fromClause;

    private String whereClause;

    private String groupClause;

    private String orderClause;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.firePropertyChange("id", this.id, this.id = id);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.firePropertyChange("name", this.name, this.name = name);
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.firePropertyChange("type", this.type, this.type = type);
    }

    public String getArgs() {
        return args;
    }

    public void setArgs(String args) {
        this.firePropertyChange("args", this.args, this.args = args);
    }

    public String getUpdateTable() {
        return updateTable;
    }

    public void setUpdateTable(String updateTable) {
        this.firePropertyChange("updateTable", this.updateTable, this.updateTable = updateTable);
    }

    public String getDoUpdateWhere() {
        return updateWhere;
    }

    public void setDoUpdateWhere(String doUpdateWhere) {
        this.firePropertyChange("updateWhere", this.updateWhere, this.updateWhere = doUpdateWhere);
    }

    public String getFromClause() {
        return fromClause;
    }

    public void setFromClause(String fromClause) {
        this.firePropertyChange("fromClause", this.fromClause, this.fromClause = fromClause);
    }

    public String getWhereClause() {
        return whereClause;
    }

    public void setWhereClause(String whereClause) {
        this.firePropertyChange("whereClause", this.whereClause, this.whereClause = whereClause);
    }

    public String getGroupClause() {
        return groupClause;
    }

    public void setGroupClause(String groupClause) {
        this.firePropertyChange("groupClause", this.groupClause, this.groupClause = groupClause);
    }

    public String getOrderClause() {
        return orderClause;
    }

    public void setOrderClause(String orderClause) {
        this.firePropertyChange("orderClause", this.orderClause, this.orderClause = orderClause);
    }

    @Override
    public String toString() {
        return "DOModel [id=" + id + ", name=" + name + "]";
    }

    @Override
    public int dataValueHashCode() {
        int code = 0;
        if (id != null) {
            code += id.hashCode();
        }
        if(name != null){
            code += name.hashCode();
        }
        if(type != null){
            code += type.hashCode();
        }
        if(args != null){
            code += args.hashCode();
        }
        if(updateTable != null){
            code += updateTable.hashCode();
        }
        if(updateWhere != null){
            code += updateWhere.hashCode();
        }
        if(fromClause != null){
            code += fromClause.hashCode();
        }
        if(whereClause != null){
            code += whereClause.hashCode();
        }
        if(groupClause != null){
            code += groupClause.hashCode();
        }
        if(orderClause != null){
            code += orderClause.hashCode();
        }
        return code;
    }

}

this class is used in ORM, when one or more property of DOModel's instance is changed, I need to persist the DOModel's instance back to database.

so there is a problem for me: how can I know a DOModel instance object is modified compared to a specific time ?

please notice the method dataValueHashCode, I use a combination of the hash code of all the properties to measure if a model is changed.the basic flow is:

1.load the a DOModel object from database
2.call dataValueHashCode method and cache it
3.(optional)modify property values
4.when need to save the object back to database, call dataValueHashCode  method again
and compare it  to the cached  one
5.if match, no change. if not match, save  it back to database.

It seems that works right now, but as a java newbie, I am worrying there is potential problems. so before I go further, I want to prove my way will not lead me to a wrong place.

As a Chinese, my English is not good enough. if yo开发者_如何学Pythonu have problem to understand what I am talking about, please post comment, I will try my best to edit this question.

thanks a lot!


There is something potentially wrong with that approach: two different objects may have the same hashCode value (the contract for hashcode is only that if a.equals(b) is true, then a.hashCode == b.hashCode, theoretically, all hashCodes could return 1 they would still be valid albeit inefficient)

So you need to come up with a cryptographic hash of yours that doesn't use hashcode, if you want to be absolutely certain it reflects your object change. I suggest using MD5 encryption, which (almost) uniquely identifies a string. It's not completely collision-resistant (means theoretically, there are multiple strings with the same output), but in practice, it's good enough.

http://en.wikipedia.org/wiki/MD5

It's quite easy to do in Java:

final MessageDigest messageDigest = MessageDigest.getInstance("MD5");
final byte[] data = stringToConvert.getBytes(); 
messageDigest.update(data,0,data.length);
final BigInteger hash = new BigInteger(1,messageDigest.digest());
return String.format("%1$032X", hash);


That sounds like you're relying on "equal hash codes imply equal objects" which is not safe to rely on.

Assuming a proper implementation of hashCode, you should be able to rely on "different hash codes mean unequal objects" - but the reverse is not true.

In particular, an implementation of:

@Override public int hashCode() {
    return 0;
}

is always valid. Sucky, but valid.


If you want to be sure that there is no change you have to compare the contents of the attributes rather than the hash code. For that you should implement the equals method. The problem with the hash code is that though unlikely it can be the same value for different property values.


This is not the way to override hashCode(). Joshua Bloch tells you the correct way to do it in chapter 3 of his "Effective Java".


It seems that works right now, but as a Java newbie, I am worrying there is potential problems.

It's not a safe approach: A change in an object, does not guarantee that the objects hash code changes.

Keep in mind that a hash code is simply an int. If your object have more than 232 states (as in your case) you are bound to have hash collisions.


A few more pointers regarding your code:

  • When overriding hashCode, you need to also override equals.
  • Your hashCode implementation is not very good (it doesn't provide a very good distribution)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜