HashMap
HashMap
1.HashMap集合底层是哈希表(散列表)的数据结构,哈希表是一个数组(长于查询)和单向链表(长于增删)的集合体,拥有数组和链表的优点
2.HashMap集合底层的源代码:
public class HashMap{ //HashMap底层实际上是一个数组(一维数组) Node<K,V> table; //静态内部类HashMap.Node static class Node<K,V>{ final int hash;//哈希值(哈希值是key的hashCode()方法的执行结果,hash值通过哈希算法可以转换成数组的下标) final K key; //存储到Map集合中的那个key V value; //存储到Map集合中的那个value Node<K,V>next; //下一个节点的内存地址 } } 哈希表(散列表):一维数组,这个数组中每一个元素是一个单向链表
注:哈希表(散列表):一维数组,这个数组中每一个元素是一个单向链表
3.put方法原理

注:同一个单向链表上所有节点的hash值相同,因为他们的数组下标是一样的。但是k和k的equals方法肯定返回的是false,都不相等。
4.get方法原理

5.总结:

思考:为什么放在HashMap集合key部分的元素需要重写equals()方法?
原因:因为equals默认比较的是两个对象的内存地址,但是这里需要比较内容是否一样.!!
6.HashMap集合key部分的特点
无序,不可重复。
无序的原因:增加的数据不一定挂到哪个单向链表上
不可重复原因:equals方法保证HashMap集合的key不可重复,如果key重复了value会覆盖掉。
注:放在HashMap集合key部分的元素其实就是放到HashSet集合中了,所以HashSet集合中的元素需要同时重写HashCode()和equals()方法。
7.重写HashCode()方法时注意的事项

8.HashMap集合的默认初始化容量是16,默认加载因子是0.75,默认加载因子是当HashMap集合底层数组的容量达到0.75的时候,数组开始扩容。
注:HashMap集合初始化容量必须是2的倍数,这样可以达到散列均匀。
9.重写equals()方法
未重写:
package MapTest; public class Student { private String name; public Student(){ } public Student(String name){ this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package MapTest; public class HashMapTest02 { public static void main(String[] args){ Student s1=new Student("张三"); Student s2=new Student("张三"); //未重写equals方法,比较的是两个对象的内存地址,这里内存地址不同,所以返回的是false System.out.println(s1.equals(s2)); } }
运行结果:false
重写:
package MapTest; public class Student { private String name; public Student(){ } public Student(String name){ this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } //重写equals方法 public boolean equals(Object obj){ if(obj==null||!(obj instanceof Student)) return false; if(obj==this)return true; Student s=(Student)obj; if(this.name.equals(s.name))return true; return false; } }
package MapTest; public class HashMapTest02 { public static void main(String[] args){ Student s1=new Student("张三"); Student s2=new Student("张三"); System.out.println(s1.equals(s2)); } }
运行结果:true
10.重写HashCode()方法
未重写(此时equals方法已经重写了)
1 package MapTest; 2 3 public class Student { 4 5 private String name; 6 7 public Student(){ 8 9 } 10 11 public Student(String name){ 12 this.name=name; 13 } 14 15 public String getName() { 16 return name; 17 } 18 19 public void setName(String name) { 20 this.name = name; 21 } 22 23 //重写equals方法 24 public boolean equals(Object obj){ 25 if(obj==null||!(obj instanceof Student)) return false; 26 if(obj==this)return true; 27 Student s=(Student)obj; 28 if(this.name.equals(s.name))return true; 29 return false; 30 31 } 32 33 34 }

接着:s1.equals(s2)结果是true,表示s1和s2是一样的,那么往HashSet里面放的话,按说只能放进去一个,因为HashSet集合的特点是:无序不可重复。
1 package MapTest; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 public class HashMapTest02 { 7 8 9 public static void main(String[] args){ 10 11 Student s1=new Student("张三"); 12 13 Student s2=new Student("张三"); 14 15 16 17 System.out.println(s1.equals(s2)); 18 19 //未重写HashCode方法 20 System.out.println("s1的HashCode值------>"+s1.hashCode()); 21 System.out.println("s2的HashCode值------>"+s2.hashCode()); 22 23 //s1.equals(s2)结果是true,表示s1和s2是一样的,那么往HashSet里面放的话,按说只能放进去一个,因为HashSet集合的特点是:无序不可重复。 24 Set<Student>students=new HashSet<Student>(); 25 26 students.add(s1); 27 students.add(s2); 28 for(Student s:students){ 29 System.out.println(s); 30 } 31 } 32 33 }
运行结果:

可以看到:存入了两个数据,原因是:虽然两者的内容一样(equals为true),但是未重写HashCode方法,导致两者的hash值不同,所以存入了两个数据,这个时候就需要重写HashCode方法了。
注:向Map集合中存,以及从Map集合中取,都是先调用key的HashCode方法,然后再调用equals方法。equals方法有可能调用,也有可能不调用。

所以,一个类的equals方法重写了,它的HashCode方法也需要重写。且equals方法返回的如果是true,那么要保证HashCode返回的值必须一样。需要注意的是,这两个方法不用自己重写,自动生成,必须保证同时生成。
1 package MapTest; 2 3 public class Student { 4 5 private String name; 6 7 public Student(){ 8 9 } 10 11 public Student(String name){ 12 this.name=name; 13 } 14 15 public String getName() { 16 return name; 17 } 18 19 public void setName(String name) { 20 this.name = name; 21 } 22 23 @Override 24 public int hashCode() { 25 final int prime = 31; 26 int result = 1; 27 result = prime * result + ((name == null) ? 0 : name.hashCode()); 28 return result; 29 } 30 31 @Override 32 public boolean equals(Object obj) { 33 if (this == obj) 34 return true; 35 if (obj == null) 36 return false; 37 if (getClass() != obj.getClass()) 38 return false; 39 Student other = (Student) obj; 40 if (name == null) { 41 if (other.name != null) 42 return false; 43 } else if (!name.equals(other.name)) 44 return false; 45 return true; 46 } 47 48 /* 49 //重写equals方法 50 public boolean equals(Object obj){ 51 if(obj==null||!(obj instanceof Student)) return false; 52 if(obj==this)return true; 53 Student s=(Student)obj; 54 if(this.name.equals(s.name))return true; 55 return false; 56 57 } 58 */ 59 60 61 62 63 }
1 package MapTest; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 public class HashMapTest02 { 7 8 9 public static void main(String[] args){ 10 11 Student s1=new Student("张三"); 12 13 Student s2=new Student("张三"); 14 15 16 17 System.out.println(s1.equals(s2)); 18 19 //未重写HashCode方法 20 System.out.println("s1的HashCode值------>"+s1.hashCode()); 21 System.out.println("s2的HashCode值------>"+s2.hashCode()); 22 23 //s1.equals(s2)结果是true,表示s1和s2是一样的,那么往HashSet里面放的话,按说只能放进去一个,因为HashSet集合的特点是:无序不可重复。 24 Set<Student>students=new HashSet<Student>(); 25 26 students.add(s1); 27 students.add(s2); 28 for(Student s:students){ 29 System.out.println(s); 30 } 31 } 32 33 }
运行结果

注:

11.HashMap与Hashtable的区别
HashMap的key值和value可以为null,而Hashtable的key值和value值都不能为null。
HashMap不是线程安全的,而Hashtable是线程安全的。

浙公网安备 33010602011771号