前度字符串转数组_java中的hashcode 前度刘郎

hashcode的作用

对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode。在Java中也一样,hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap以及HashTable。

当向集合中插入对象时,如何判别在集合中是否已经存在该对象了?也许大多数人都会想到调用equals方法来逐个进行比较,这个方法确实可行。但是如果集合中已经存在一万条数据或者更多的数据,如果采用equals方法去逐一比较,效率必然是一个问题。此时hashCode方法的作用就体现出来了,当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashcode值。实际上在HashMap的具体实现中会用一个table数组保存HashMap的对象,并且在table数组中存放的Entry对象中保存着存放对象的hash值。如果table中没有该hashcode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用equals方法的次数就大大降低了。

更加通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。可以把hashcode简单的理解为对象存储的物理地址。

看一下HashMap的put()方法的源代码便可以很好的理解hashcode的作用了。

48304ba5e6f9fe08f3fa1abda7d326ab.png

1 publicV put(K key, V value) {

2 if (table ==EMPTY_TABLE) {

3 inflateTable(threshold);

4 }

5 if (key == null)

6 returnputForNullKey(value);

7 int hash =hash(key);

8 int i =indexFor(hash, table.length);

9 for (Entry e = table[i]; e != null; e =e.next) {

10 Object k;

11 if (e.hash == hash && ((k = e.key) == key ||key.equals(k))) {

12 V oldValue =e.value;

13 e.value =value;

14 e.recordAccess(this);

15 returnoldValue;

16 }

17 }

18

19 modCount++;

20 addEntry(hash, key, value, i);

21 return null;

22 }

48304ba5e6f9fe08f3fa1abda7d326ab.png

put方法是用来向HashMap中添加新的元素,从put方法的具体实现可知,会先调用hashCode方法得到该元素的hashCode值,然后查看table中是否存在该hashCode值,如果存在则调用equals方法重新确定是否存在该元素,如果存在,则更新value值,否则将新的元素添加到HashMap中。从这里可以看出,hashCode方法的存在是为了减少equals方法的调用次数,从而提高程序效率。

是否可以使用hashcode来判断对象是否相等呢?不同的对象可能会生成相同的hashcode值。虽然不能根据hashcode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等,如果两个对象的hashcode值不等,则必定是两个不同的对象。如果要判断两个对象是否真正相等,必须通过equals方法。

总结一下:

1、如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;

2、如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;

3、如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;

4、如果两个对象的hashcode值相等,则equals方法得到的结果未知。

equals方法和hashCode方法

在设计一个类的时候,如果要重写equals方法,必须重写hashCode方法。

下面例子说明了hashcode()和equal()方法的作用:

48304ba5e6f9fe08f3fa1abda7d326ab.png

1 public classStudent {

2 private intid;

3 privateString name;

4 public Student(intid, String name) {

5 super();

6 this.id =id;

7 this.name =name;

8 }

9 public intgetId() {

10 returnid;

11 }

12 publicString getName() {

13 returnname;

14 }

15 public void setId(intid) {

16 this.id =id;

17 }

18 public voidsetName(String name) {

19 this.name =name;

20 }

21 @Override

22 public booleanequals(Object obj) {

23 Student student =(Student)obj;

24 return this.id==student.getId()&&this.name.equals(student.getName());

25 }

26

27 }

48304ba5e6f9fe08f3fa1abda7d326ab.png

48304ba5e6f9fe08f3fa1abda7d326ab.png

1 public classTest {

2 public static voidmain(String[] args) {

3 Student s1 = new Student(18, "Jack");

4

5 System.out.println(s1.hashCode());

6 Map map = new HashMap();

7

8 map.put(s1, "1");

9

10 System.out.println(map.get(new Student(18, "Jack")));

11 }

12 }

48304ba5e6f9fe08f3fa1abda7d326ab.png

这段代码输出的结果为null,就是因为重写equals方法的同时忘记重写hashCode方法。hashCode方法是将对象的存储地址进行映射。上面的s1和新生成的对象是两个不同的对象,存储地址不一样,所有输出null。

在HashMap的get()方法如下:

48304ba5e6f9fe08f3fa1abda7d326ab.png

1 publicV get(Object key) {

2 if (key == null)

3 returngetForNullKey();

4 Entry entry =getEntry(key);

5

6 return null == entry ? null: entry.getValue();

7 }

8 final EntrygetEntry(Object key) {

9 if (size == 0) {

10 return null;

11 }

12

13 int hash = (key == null) ? 0: hash(key);

14 for (Entry e =table[indexFor(hash, table.length)];

15 e != null;

16 e =e.next) {

17 Object k;

18 if (e.hash == hash &&

19 ((k = e.key) == key || (key != null &&key.equals(k))))

20 returne;

21 }

22 return null;

23 }

48304ba5e6f9fe08f3fa1abda7d326ab.png

可以看出在HashMap的get()方法中线比较hashcode值,如果hashcode相等,然后再进行比较equal()方法是否相等。

所以上述例子如果想输出1,必须要重写hashcode和equal方法,并且让equals方法和hashCode方法始终在逻辑上保持一致性。

总结一下:

1、在程序执行期间,只要equals方法的比较操作用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法必须始终如一地返回同一个整数。

2、如果两个对象根据equals方法比较是相等的,那么调用两个对象的hashCode方法必须返回相同的整数结果。

3、如果两个对象根据equals方法比较是不等的,则hashCode方法不一定得返回不同的整数。

另外,在设计hashCode方法和equals方法的时候,如果对象中的数据易变,则最好在equals方法和hashCode方法中不要依赖于该字段。如上面例子,学生添加一个年龄字段,如果hashcode依赖于年龄字段,那么每年对象的hashcode值是不一样的,所在HashMap的get方法就会取不到对象。

hashcode是用来区分对象是否相等的第一步,用hashcode可以减少比较时间。不能在对象加入到Hash容器中时修改对象属性,这样会导致内存泄漏(内存中的对象不能被正常清除掉)。Hash值只能针对hash容器来说。存放在Hash容器中的对象要认真设计hashcode()方法,减少hashcode冲突,这样其底层基本上是以数组实现的,否则就会退化为链表实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值