深度解析hashcode

1.hashcode的取值范围?

2.hashcode和equals的区别?

对于第一个问题,hashcode返回类型为int,则知取值范围为:

 

Integer.MIN_VALUE   ----  Integer.MAX_VALUE

int最大值最小值,根据编译器类型不同而变化:

public static void main(String[] args) {

        // hashcode 取值范围的问题。
        //int类型的最大值和最小值,根据编译器的不同而取值范围有所不同
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MIN_VALUE);


        int a  =  0x7FFFFFFF;
        int b  =  0x7FFFFFFF+1;
        //Integer.MIN_VALUE : 0x7FFFFFFF == 2^31-1
        //Integer.MAX_VALUE : 0x7FFFFFFF +1 == -2^31
        System.out.println(a);
        System.out.println(b);
    }

hashcode的取值范围在32以上编译器为 -2^31 到 2^31-1,java采用的是2进制补码机制,第一位符号位,最大值为0x7FFFFFFF,即(2147483647)。

第二个问题示例说明:

public class Emp {
	private int empno;
	private String empname;
	private String dept;
	public int getEmpno() {
		return empno;
	}
	public void setEmpno(int empno) {
		this.empno = empno;
	}
	public String getEmpname() {
		return empname;
	}
	public void setEmpname(String empname) {
		this.empname = empname;
	}
	public String getDept() {
		return dept;
	}
	public void setDept(String dept) {
		this.dept = dept;
	}
	public Emp(int empno, String empname, String dept) {
		super();
		this.empno = empno;
		this.empname = empname;
		this.dept = dept;
	}
	public Emp() {
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Emp [empno=" + empno + ", empname=" + empname + ", dept="
				+ dept + "]";
	}
	@Override
	public int hashCode() {//注意,这里重写与否决定于结果
		final int prime = 31;
		int result = 1;
		result = prime * result + empno;
		return result;
	}


	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Emp other = (Emp) obj;
		if (empno != other.empno)
			return false;
		return true;
	}
	
}

用hashmap测试:

public class TestHashMap {
    public static void main(String[] args) {

        Emp emp1= new Emp(1000,"张三","xx");
        System.out.println(emp1.hashCode());
        HashMap<Emp, String> hm = new HashMap<Emp,String>();
        hm.put(emp1, "hello");
        //修改对象emp1来判断是否hashcode是否发生变化
        emp1.setEmpno(10001);
        emp1.setDept("李四光");
        System.out.println(emp1.hashCode());

        System.out.println(hm.get(emp1));

    }
}

 

Emp中不重写时输出结果:

1134517053
1134517053
hello

Emp中重写时输出结果:

1031
10032
null

结论:

 

这里Emp类中如果用jdk提供的默认hashcode方法,你会发现仍能够取到value值 hello,尽管key发生了变化(这里的变化是对象值发生了变化,但是地址没有变);

但是如果在Emp类中重写hashcode,会发现取值为空;

猜想可能源于jdk的默认的hashcode方法产生的值是以对象的地址生成的,而跟对象的值没有任何关系。所以为什么上面对象改变了,但是hashcode 是一样的。

这里可以延伸另外一个问题,hashcode 和 equals比较的问题,equals相等则 hashcode一定相等,但是hashcode相等equals未必相等,上面的示例就很好的证明了这个结论:

equals相等则 地址必定相同,地址相同则产生的 hashcode值 一定相等;

hashcode相等,可能是相同地址的不同对象产生的,所以equals有可能不同的。

 

实战:

    对于需要大量并且快速的对比的话如果都用equal()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!

     这种大量的并且快速的对象对比一般使用的hash容器中,比如hashset,hashmap,hashtable等等,比如hashset里要求对象不能重复,则他内部必然要对添加进去的每个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),如果hashCode()相同,再用equal()验证,如果hashCode()都不同,则肯定不同,这样对比的效率就很高了。

 

测试HashSet

public class TestHashSet {
    public static void main(String[] args) {
        HashSet<Emp> set = new HashSet<Emp>();
        Emp emp1= new Emp(1000,"zhangsan","xx");
        Emp emp2= new Emp(1000,"zhangsan","xx");
        set.add(emp1);
        set.add(emp2);
        
        System.out.println(set.size());


    }
}

不重写hashcode的情况下,emp1和emp2因为地址不相同,产生hashcode是不一样的,根据上面的结论,由于hashcode是不一样的,则直接认定是两个对象放到set中,不再执行equals方法进行判断;

输出结果为2.

重写hashcode 和 equals 情况下 , emp1和emp2默认也是会认为是两个对象,虽然地址不相同,但调用重写的hashcode后,产生的hashcode值是相同的,根据上面的结论,由于hashcode是一样的,会再根据equals来进行判断是否是相同对象。

输出结果为1.

 

tip:

此处说的hashcode()是Object的native方法,如果是String,由于重写hashcode(), 则与值产生了关系,而与地址没有关系,String 的 hashcode()源码如下:

public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

 

ref:

https://zhidao.baidu.com/question/537818957.html

https://blog.csdn.net/is01753/article/details/74912530

https://blog.csdn.net/pozmckaoddb/article/details/47447429

https://www.cnblogs.com/keyi/p/7119825.html

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值