关于Java中HashMap和HashSet

本文深入探讨了HashMap与HashSet的工作原理,包括它们的数据存储方式、扩容机制及内部实现细节。此外,通过具体示例展示了如何使用这些集合类,并解释了hashCode与equals方法的重要性。

HashMap:存储形式key-value,它并不是线程安全的。初始容量:一般是16,加载因子:一般0.75,至于这两个概念,就不多说了。当数据量达到当前容量*加载因子,容量就是成倍扩展。

HashSet: 存储形式就是一个对象了,不是线程安全的。初始容量:一般是16,加载因子:一般0.75


再说HashMap存储形式,我就语言描述了,不对之后,还望您指正。

比如我们进行下面的步骤:

Map<Integer,String> worker = new HashMap<Integer,String>();
worker.put(1, "张三");
worker.put(2, "李四");

Java的装箱拆箱我就不说了。当向map中插入数据的时候,先计算key的Hash值,假如hash到map的对应位置发现这个位置为null,则可以把此对象存入到这次,当然只是一个指向此对象的链接。如果此处不是null,也就是它hash后的位置被被人占据了,那么它就要和这个占据着者比较一下了,如果key是相同的,那么就把占据着的value改成自己的,如果key不是相同的,那么就默默地自己搞个链接也指向自己,这样从map中也能找到自己。

比如:

Map<Integer,String> worker = new HashMap<Integer,String>();
worker.put(1, "张三");
worker.put(1, "李四");
System.out.println(worker.get(1));

此时会打印出李四。这个我们就不奇怪了。

再看取元素,如果get时候拿到的key进行同样方法的hash之后找不到对象,当然就返回null,如果找到一个这个位置有对象,那么就和他比较一下,key相同就返回,不相同就比较此处链接的其他对象,实在都不相同,那就返回null;


关于HashSet,它底层用的是HashMap,它存入的值被用成HashMap的key,至于map的value,value 则存储了一个 PRESENT,它是一个静态的 Object 对象。(这个我木有研究过,有了解的希望不吝赐教,先在此谢过~~)。其余的存取就和HashMap一样了。

下面搞个例子试试:

public class Test {
	public static void main(String [] args){
		Set<Name> mySet = new HashSet<Name>();
		Name name1 = new Name("张","三");
		Name name2 = new Name("张","三");
		mySet.add(name1);
		mySet.add(name2);
		System.out.println(mySet);
	}
}
class Name{
	private String first;
	private String last;
	public Name(String f,String l){
		this.first  = f;
		this.last = l;
	}
	
	@Override
	public String toString() {
		
		return "first:"+this.first+";last:"+this.last;
	}
	
}
这个会输入两个“张三”,都能成功,输出就是:[first:张;last:三, first:张;last:三]。

那不是Hash算法重写以后呢?再看:


public class Test {
	public static void main(String [] args){
		Set<Name> mySet = new HashSet<Name>();
		
		Name name1 = new Name("张","三");
		Name name2 = new Name("张","三");
		mySet.add(name1);
		mySet.add(name2);
		System.out.println(mySet);
	}
}
class Name{
	private String first;
	private String last;
	public Name(String f,String l){
		this.first  = f;
		this.last = l;
	}
	
	@Override
	public int hashCode() {
		
		return this.first.hashCode();
	}
	@Override
	public String toString() {
		
		return "first:"+this.first+";last:"+this.last;
	}
	
}
这样总会只进去一个了吧,但是输出结果:[first:张;last:三, first:张;last:三]

那,equals方法重写,再看:

public class Test {
	public static void main(String [] args){
		Set<Name> mySet = new HashSet<Name>();
		
		Name name1 = new Name("张","三");
		Name name2 = new Name("张","三");
		mySet.add(name1);
		mySet.add(name2);
		System.out.println(mySet);
	}
}
class Name{
	private String first;
	private String last;
	public Name(String f,String l){
		this.first  = f;
		this.last = l;
	}
	public boolean equals(Object n){
		if(this==n)
			return true;
		if(n.getClass() == Name.class){
			Name nn = (Name)n;
			return nn.first.equals(this.first) && nn.last.equals(this.last);
		}
		return false;
	}
	@Override
	public int hashCode() {
		
		return this.first.hashCode();
	}
	@Override
	public String toString() {
		
		return "first:"+this.first+";last:"+this.last;
	}
	
}
这次结果是:[first:张;last:三],我们才明白HashSet在进行存储时候Hash方法和对象自己的方法hashCode,进行比较和对象自己的equals方法是有关系的。那每个对象都有的方法有几个呢,看下面:

protected Object clone() throws CloneNotSupportedException{}

protected void finalize() throws Throwable {}

public int hashCode() {}

public String toString() {}

public boolean equals(Object obj) {}

貌似这个问题面试常问,哈哈~~


希望您能有收获,本人能力有限,如果哪里有学的不到的地方,望您不吝赐教,先在此谢过~~

最后,这篇文章不错,李刚老师发表的:

点击打开链接









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值