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是线程安全的。

posted @ 2021-01-15 23:25  L1998  阅读(119)  评论(0)    收藏  举报