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:
把本来的TestBean@d5682s78,这样的日志输出内容,改成其他的更清晰的方式。有两张一种是上面的那种方式,还有一种是格式化的输出方式。
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; }
还可以采用“延迟加载”,但这样的方法会造成代码复杂性提高,代码可阅读行降低。