欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于Hibernate ORM映射实体通用hashCode与equals方法的实现

程序员文章站 2022-05-24 12:01:18
...
公司框架使用的是spring mvc +spring+hibernate 各个版本都很新,hibernate主要使用的是注解映射,说实话,对开发上来说,比xml配置文件要方便得多,而且注解也支持继承,因此父类的实现可以大大降低工作量了,想以前hibernate还是配置文件的年代的时候,很多表的字段是重复固定的,如ID,创建人,创建时间等等,那个时候虽然java层面的实体可以基类,然后通过继承来减轻工作量,可是配置文件却要每个xml都复制一道(也许有方便的方式,可惜我没找到),现在有了注解,就不用这样恶心的复制了。
其实前面废话这么多,也就做个铺垫,因为这次主要说说的是hashCode与equals方法,hashCode方法很多开发人员也许不会有多少感性的认知,但是更多的人对equals方法应该很熟悉才是,hashCode方法其实与其一样,也是用于对象比较的,且其更实用(就是获得其值比较大小,很多jdk内置的一些工具的比较与排序都是使用其来完成的,因此它是一个极其重要的方法)。对于java的一些开发规范来说,对于一个java类的开发,必须实现hashCode与equals来重实现对象比较逻辑。
这次主要任务就是要实现一个hibernate映射父类的hashCode方法与equals方法,因为我并不希望每一个orm映射类都要去实现一个这样的方法,其一这没有必要,其二也为了大大减轻一些工作量,最终目的也是能够实现一个能够适用于jdk一些内置工具的orm映射体系,不会让orm对象在使用HashSet或者Map之类的工具时,让orm 对象表得奇怪。
对于表的映射orm的比较其实逻辑上多很简单,我们约定每个表的内置主键名都是id字段,因此同一个orm映射对象的比较,只要比较id就可以了,id不同的话,那么表示此对象不同,否则就相同,排序也根据其来排序。
初步的实现为下
	public int hashCode() {
		return id.intValue();
	}

	public boolean equals(Object obj) {
		
		return this.id.longValue()==entity.id.longValue();
	}

我们的id是java.lang.Long类型的,因此转换成hashCode需要intValue()一下。
但是我们实现的逻辑在父类中,也就是说,这两个方法会被其继承的子类所使用,而不同子类映射不同的表,而不同的表中所生成的主键id是完全可以相同的,在这里比对ID之前,必须比对类型,这样就可以确保对象的比对是在同一个类型下比较的,于是在之前加入如下代码:
	public int hashCode() {
                int id=this.id==null?0:this.id.intValue();
		return id^this.getClass().getName().hashCode();
	}

	public boolean equals(Object obj) {
		if(!this.getClass().getName().equals(obj.getClass().getName())){
			return false;
		}
		return this.id.longValue()==entity.id.longValue();
	}

这里为什么不直接比较Class,而要比较Class对象的name属性,因为Class没有自己实现hashCode方法与equals方法,且某个类的Class对象在虚拟机中也不一定会是单例的,因为同样的类可能由不同的类装载器完成装载,这样在虚拟机中就会存在两个完全相同的类的Class对象,而且这两个对象会在一些时候碰头,最典型的例子就是你用oracle驱动包中的Timestamp的class模板去比较一个由jdbc装载的一个Timestamp对象的getClass的模板,你会发现它们的全限定名完全相同,但是equals却返回false。因此此处必须比较name,因为name转换为String,比较是不会出现歧义的。
在使用一段时间后,又发现问题,比较类模板也是不行的,这是因为hibernate的延迟加载机制的缘故,因为延迟加载改变了原始的类模板,使用了重新生成的代理类,这时,我们自己生产的对象与hibernate装载的对象,我们自以为是相同的,但实际却不同,因为我们使用的类模板是原始类模板,而hibernate装载的却是修改过的代理类模板,如此一来,简单的类模板比对则无用了,后来经过我冥思苦想,终于找到一个替代性的办法,也许这个方式并不成熟,因为我们使用的是注解,因此我打算利用注解的@Table的name属性来完成比对(我们规定每个orm映射都要指定表名,因此这种方式对我们的系统来说可行的),如今代码如下,这是先行版的完整代码:
	public int hashCode() {
		String tableName=this.tableName();
		int id=this.id==null?0:this.id.intValue();
		if(StringUtils.isNotBlank(tableName)){
			return id^tableName.hashCode();
		}else{
			return id^this.getClass().hashCode();
		}
		
	}

	public boolean equals(Object obj) {
		if(obj==null){
			return false;
		}
		if(!(obj instanceof IdEntity)){
			return false;
		}
		IdEntity entity=(IdEntity) obj;
		if(this.id==null||entity.id==null){
			return false;
		}
		boolean typecheck=false;
		if(StringUtils.isNotBlank(this.tableName())){
			this.tableName().equals(entity.tableName());
		}else{
			typecheck=this.entityName().equals(entity.entityName());
		}
		return (this.id.longValue()==entity.id.longValue())&&typecheck;
	}

里面实现了一些equals的一些其它标准。
相关标签: java