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) {}
貌似这个问题面试常问,哈哈~~
希望您能有收获,本人能力有限,如果哪里有学的不到的地方,望您不吝赐教,先在此谢过~~
最后,这篇文章不错,李刚老师发表的:
本文深入探讨了HashMap与HashSet的工作原理,包括它们的数据存储方式、扩容机制及内部实现细节。此外,通过具体示例展示了如何使用这些集合类,并解释了hashCode与equals方法的重要性。
1304

被折叠的 条评论
为什么被折叠?



