自定义对象需要重写hashcode

      Java中的很多对象都override了equals方法,都知道,这是为了能比较两个对象是否相等而定义,如果不需要比较,则不需要定义equals方法。比如StringBuffer类,没有提供equals方法,则说明没有两个StringBuffer对象是相等的。再比如Collections类,全部是静态方法,根本没必要创建对象,所以也就没有提供equals方法。       我们程序中自定义的对象有时候需要比较它们是否相等,也需要重写equals方法。如果我们要将对象放到HashMap或者Hashtable这样的hash集合中的时候,就需要重写hashcode方法了。因为它们是根据hashcode来标识对象的。       如果我们不重写hashcode方法,把他们作为key放入hashmap中是什么情况呢?看看下面代码:

import java.util.HashMap;

public class HashTest {

	public static void main(String...args) {
		MyBean a = new MyBean();
		a.x = 1;
		a.s = "xyz";
		MyBean b = new MyBean();
		b.x = 1;
		b.s = "xyz";
		HashMap<MyBean, String> map = new HashMap<MyBean, String>();
		map.put(a, "a");
		map.put(b, "b");
		System.out.println("a equals b:"+a.equals(b));
		System.out.println("map size:"+map.size());
		System.out.println("a:"+map.get(a));
		System.out.println("b:"+map.get(b));
	}
}

class MyBean {
	int x;
	String s;
	@Override
	public boolean equals(Object obj) {		
		if(this == obj) return true;
		if(!(obj instanceof MyBean)) return false;
		if(((MyBean)obj).x == x) return true;
		return false;
	}
}

      结果如下:

a equals b:true map size:2 a:a b:b  

      a和b明明是相等的,可是放进hashmap中之后,却被认为是两个对象,很诡异哦。       下面加上hashcode,再看看什么结果:

class MyBean {
	int x;
	String s;
	@Override
	public boolean equals(Object obj) {		
		if(this == obj) return true;
		if(!(obj instanceof MyBean)) return false;
		if(((MyBean)obj).x == x) return true;
		return false;
	}
	@Override
	public int hashCode() {
		return (s!=null?s.hashCode():1)*31+x;
	}
}

     结果如下:

a equals b:true map size:1 a:b b:b

      这样才保证了相等的对象在hash集合中也相等。计算hashcode的时候,一般使用关键的属性的hashcode值。计算hashcode的属性较多则计算复杂,降低了效率,若较少的属性计算,则重复的hashcode较多,同样降低性能,写一个好的hashcode方法,还比较难。       所以,我们重写equals的时候,一定要重写hashcode方法。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏老马说编程

(53) 剖析Collections - 算法 / 计算机程序的思维逻辑

之前几节介绍了各种具体容器类和抽象容器类,上节我们提到,Java中有一个类Collections,提供了很多针对容器接口的通用功能,这些功能都是以静态方法的方式...

24290
来自专栏青玉伏案

窥探Swift之别样的枚举类型

  想必写过程序的童鞋对枚举类型并不陌生吧,使用枚举类型的好处是多多的,在这儿就不做过多的赘述了。Fundation框架和UIKit中的枚举更是数不胜数,枚举可...

21270
来自专栏个人随笔

Java 抽象类与final用法

 抽象类: 基于继承 抽象类和抽象方法的定义 父类的意义:  把子类共有的属性,抽取出来,达到代码的重用 抽象类不可被实例化 使用抽象类,限制实例化(只有派生类...

33970
来自专栏C++

python笔记:#005#算数运算符

18820
来自专栏黑泽君的专栏

关于Java面向对象的分析题

分析程序看有没有问题,如果有,说出原因即可。 ---------------------------------------------------------...

13010
来自专栏Java成长之路

六、jvm之如何判断对象已死?

在堆里面几乎存放中Java程序运行所动态生成的所有对象,垃圾回收器在对堆进行回收前,第一件事情就是要确定这些对象之中还有哪些存活,哪些已经死去(即不可能再被任何...

8020
来自专栏向治洪

数据结构之串

基本概念 串(string)是由零个或多个字符组成的有限序列,又名叫字符串。形如s="a,b,c.."。ai(1 ≤ i ≤ n)可以是字母、数字或其他字符,i...

28180
来自专栏JavaEdge

SpringBoot2.0响应式编程系列(二)-函数式编程和lambda表达式函数接口方法引用类型推断

56530
来自专栏lgp20151222

ThreadLocal基本原理及运用

ThreadLocal提供本地线程变量。这个变量里面的值(通过get方法获取)是和其他线程分割开来的,变量的值只有当前线程能访问到,不像一般的类型比如Perso...

10420
来自专栏C/C++基础

数组中的逆序对

题目: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

12410

扫码关注云+社区

领取腾讯云代金券