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

toString、equals和hashCode重写

程序员文章站 2022-04-19 18:23:59
...

 

public class TestBean {
	private byte para1;
	private long para2;
	private double para3;
	private float para4;
	private int[] para5;
	private String para6;
	public TestBean() {
		
	}
	public TestBean(byte para1, long para2, double para3, float para4, int[] para5, String para6) {
		this.para1 = para1;
		this.para2 = para2;
		this.para3 = para3;
		this.para4 = para4;
		this.para5 = para5;
		this.para6 = para6;
	}
	
	@Override
	public String toString() {
		return "TestBean [para1=" + para1 + ", para2=" + para2 + ", para3="
				+ para3 + ", para4=" + para4 + ", para5="
				+ Arrays.toString(para5) + ", para6=" + para6 + ", hashCode()="
				+ hashCode() + "]";
	}
	
	@Test
	public void test(){
		System.out.print(1231321>>>32);
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj == null)
			return false;
		if(obj == this)
			return true;
		if(obj instanceof TestBean){
			TestBean testBean = (TestBean) obj;
			return testBean.para1 == para1 && testBean.para2 == para2 && Double.doubleToLongBits(testBean.para3) == Double.doubleToLongBits(para3) && 
					Float.floatToIntBits(testBean.para4) == Float.floatToIntBits(para4) && Arrays.equals(testBean.para5, para5) &&
					((testBean.para6 == null && para6 == null) || (testBean.para6 != null && testBean.para6.equals(para6)));
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		final int base = 31;
		int result = 17;
			result = base*result + para1;
			result = base*result + (int)(para2^(para2>>>32));
		long temp = Double.doubleToLongBits(para3);
			result = base*result + (int)(temp^(temp>>>32));
			result = base*result + Float.floatToIntBits(para4);
			result = base*result + Arrays.hashCode(para5);
			result = base*result + para6 == null ? 0 : para6.hashCode();
		return result;
	}
}

1.重写toString:

    把本来的[email protected],这样的日志输出内容,改成其他的更清晰的方式。有两张一种是上面的那种方式,还有一种是格式化的输出方式。

2.重写equals:

    重写equals必须重写hashCode。因为这个方法遵循Object的通用约定就是:

    a.同一个对象多次调用每次返回的hashCode都是相等的,而同一类型的不同对象多次被调用返回的hashCode可以不同

    b.equals相等的hashCode必定相等

    c.hashCode相等的,equals可以不等。

    equals只是两个对象逻辑上相等,并不是比较在内存中的地址值,因此不同的对象equals也可能相等。

3.重写hashCode:

    选择31作为乘数的基数,有两个原因:

        a.31是一个传统的奇数。

        b.31*x=x<<5-x

    如上述代码,hashCode重写时,为了保证良好的散列性,遵循以下原则:

        a.byte、char、short类型的数据要转化为int再相加

        b.long可以int(longnum^(longnum>>>32))相加

        c.float先转化为int,Float.floatToIntBits(fnum)

        d.Double先转化为long,Double.doubleToLongBits(dnum),剩下的操作同b

        e.Array可用Arrays.hashCode(arr)得到hashCode值

        f.Object先计算出Object的hashCode。

    通过上述步骤得到了良好散列性的hashCode但是影响了速度。因此可以稍微更改一下。加一个预存的hash值,这样不管这个对象被调用多少次,hashCode只计算一次。

    调整后:

	private volatile int hashCode = 0; //加个全局变量,volatile的意思不安全的,
                               //告诉jvm取消内存拷贝,取这个值的时候直接到内存中取
    @Override
	public int hashCode() { //调整后的hashCode方法
		
		int result = hashCode;
		
		if(result == 0){
			i++;
			final int base = 31;
			result = 17;
			result = base*result + para1;
			result = base*result + (int)(para2^(para2>>>32));
		long temp = Double.doubleToLongBits(para3);
			result = base*result + (int)(temp^(temp>>>32));
			result = base*result + Float.floatToIntBits(para4);
			result = base*result + Arrays.hashCode(para5);
			result = base*result + ((para6 == null) ? 0 : para6.hashCode());
			hashCode = result; //在这里把计算出来的result值赋给全局变量hashCode
		}
		
		return hashCode;
	}

还可以采用“延迟加载”,但这样的方法会造成代码复杂性提高,代码可阅读行降低。

转载于:https://my.oschina.net/wliming/blog/678081