软件构造心得(10):编写等价性判断时重写Hashcode的原因:理论与性能分析

首先了解hash系列数据结构一些底层依赖

hash系列数据结构在底层使用其构建对象所具有的hashcode将其分配index到表的各个位置。如果元素的hash值相同,则用链式结构将其追加到index所具有元素组的末尾。
在我们使用键值索引时,实际上数据结构是先得到这个键的hashcode然后去索引该index的数据(链)直到最后。

软件构造心得(10):编写等价性判断时重写Hashcode的原因:理论与性能分析_第1张图片

为什么要Override Hashcode

一句话概括,因为我们要保证,在我们的ADT被使用hash值作为hashset等数据结构的部分时(绝大多数情况这是不可被避免的),避免由于预设的hash值(预设的是地址,unpredictable)和我们判定两个对象等价的不一致而造成的,在使用构建好的hash结构之后引发的不可预知的错误。

即,我们要保证,当我们认为两个对象等价时,我们也要保证他们的hashcode是一样的。

使得两个被认为具有等价性的对象,具有相同的hashcode,满足这个原则,我们就可以保证程序运行的正确性了,我们的hashcode就是正确的了也就是说,无论是你结合质数重新设置了一个映射编码,还是说你单纯的直接返回像“42”这种的常数(42被号称是万事万物的答案,很显然结合实验指导书的“DON’T PANIC”,某位作者一定是银河系漫游指南的死忠粉)都是符合我们的要求的。

等价的对象的hashcode必须相等,不等价的对象的hashcode最好相等

我们虽然可以让所有元素有同一个hash值,(那他们就会在一个index上形成一个长链条),但这样一定会显著的影响各种性能。(加入,索引等)

简单的验证实验

针对不等价对象返回不同数值的代码

package P2;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;



public class PhoneNumber {


    public PhoneNumber(int areaCode,int prefix,int lineNumber){
    	this.areaCode = areaCode;
    	this.prefix = prefix;
    	this.lineNumber = lineNumber;
    }
    private final int areaCode;
	private final int prefix;
	private final int lineNumber;
	
	
	@Override
	public int hashCode() {
	int[] hashArray = {areaCode, prefix, lineNumber};
	return Arrays.hashCode(hashArray);
	}
	public static void main(String[] args) {
	}
}

所有对象返回相同值的代码

package P2;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;



public class PhoneNumber {


    public PhoneNumber(int areaCode,int prefix,int lineNumber){
    	this.areaCode = areaCode;
    	this.prefix = prefix;
    	this.lineNumber = lineNumber;
    }
    private final int areaCode;
	private final int prefix;
	private final int lineNumber;
	
	
	@Override
	public int hashCode() {
	return 42}
	public static void main(String[] args) {
	}
}

测试代码(数据量10000)

package P2;

import java.util.HashSet;
import java.util.Set;

import org.junit.Test;

public class phoneNumberTest {
	@Test(expected = AssertionError.class)
	public void testAssertionsEnabled() {
		assert false;
	}
	@Test
	public void testRuntime() {
		Set<PhoneNumber> set = new HashSet<PhoneNumber>();
		for(int i= 0;i<=10000;i++) {
			PhoneNumber testNumber = new PhoneNumber(i,i,i);
			set.add(testNumber);
	   }
	}

}

测试结果
软件构造心得(10):编写等价性判断时重写Hashcode的原因:理论与性能分析_第2张图片
软件构造心得(10):编写等价性判断时重写Hashcode的原因:理论与性能分析_第3张图片可以看到,返回无差别的hashcode对性能具有显著影响。

小结

Override equals方法时必须要伴随着override hashcode(除非你要降低对于你的ADT的质量,默认其不会参与构建任何hash系列结构);hashcode要保证等价对象的code一样,最好保证不等价对象的code不一样。

你可能感兴趣的:(java,笔记,软件构造)