HashMap and HashSet

本文深入探讨了HashMap和HashSet的工作原理,包括它们如何利用Hash算法高效地存储和检索数据。此外,文章还通过示例代码解释了Java集合实际上是如何存储对象引用的,并提供了关于HashSet元素相等性的关键细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HashMapHashSet

对于HashSet来说,系统采用Hash算法决定集合元素的存储位置,这样可以保证快速存,取集合元素;对于HashMap来说,系统将value当成key的附属,系统根据Hash算法来决定key的存储位置,这样可以保证快速存,取集合key,而value总是紧随key存储。

虽然集合号称存储的是Java对象,但实际上并不会真正将Java对象放入Set集合中,而只是在Set集合中保留这些对象的引用而已。也就是说,Java集合实际上是多个引用变量所组成的集合,这些引用变量指向实际的Java对象。

import java.util.ArrayList;

import java.util.List;

class Apple{

doubleweight;

public Apple(double weight){

this.weight = weight;

}

}

publicclass ListTest {

publicstaticvoid main(String[] args){

Apple t1 = new Apple(2.2);

Apple t2 =new Apple(1.8);

List<Apple> list = new ArrayList<Apple>(4);

list.add(t1);

list.add(t2);

System.out.println(list.get(0)==t1);

System.out.println(list.get(1)==t2);

}

}

Output:

true

true

ArrayList底层是基于数组实现的,也就是说ArrayList底层封装的是数组,每次创建时传入的int参数就是它包装的数组的长度;

对于HashMap而言,它的存储方式要比ArrayList复杂一些,采用所谓的”Hash算法来决定每个元素的存储位置。

当执行程序map.put(“yuwen”,80.0)时,系统将调用”yuwen”hashcode()方法得到其hashcode值――每个Java对象都有hashcode()方法,都可通过该方法获得它的hashcode的值。得到这个值后,系统会根据该hashcode值来决定该元素的存储位置。

HashMap在底层将key-value当成一个整体进行处理,这个整体就是一个Entry对象。HashMap底层采用一个Entry[]数组来保存所有的key-value对,当需要存储一个Entry对象时,会根据Hash算法来决定其存储位置;当需要取出一个Entry时,也会根据Hash算法找到其存储位置,直接取出该Entry。由此可见,HashMap之所以能快速存,取它所包含的Entry,完全类似于生活中,不同的东西要放在不同的位置,需要时才能快速找到它。

当创建HashMap时,有一个默认的负载因子(load factor),其默认值为0.75.增大负载因子可以减少Hash表(就是那个Entry数组)所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的操作(HashMapget()put()方法都要用到查询);减小负载因子会提高数据查询的功能,但会降低Hash表所占用的内存空间。

如果开始就知道HashMap会保存多个key-value对,可以在创建时就使用较大的初始化容器,如果Entry的数量一直不会超过极限容量(capacity*load factor)HashMap就无需调用resize()方法重新分配table数组,从而保证较好的性能。当然,开始就将初始容量设置太高可能会浪费空间(系统需要创建一个长度为capacityEntry数组),因此创建HashMap时初始化容量设置也需要小心对待。对于HashSet而言,它是基于HashMap实现的。HashSet底层采用HashMap来保存所有元素。

import java.util.HashSet;

import java.util.Set;

class Name{

private Stringfirst;

private Stringlast;

public Name(String first,String last){

this.first = first;

this.last = last;

}

publicboolean equals(Object o){

if(this == o){

returntrue;

}

if(o.getClass() == Name.class){

Name n = (Name)o;

return n.first.equals(first) && n.last.equals(last);

}

returnfalse;

}

}

publicclass HashSetTest {

publicstaticvoid main(String[] args){

Set<Name> s = new HashSet<Name>();

s.add(new Name("abc","123"));

System.out.println(s.contains(new Name("abc","123")));

}

}

Output:

False

输出false的原因是因为HashSet判断两个对象相等的标准除了要求通过equals()方法比较返回的true之外,还要求两个对象的hashCode()返回值相等,上面的程序没有重写hashCode()方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值