【java】List、Set和Map的区别

平凡也就两个字: 懒和惰;
成功也就两个字: 苦和勤;
优秀也就两个字: 你和我。
跟着我从0学习JAVA、spring全家桶和linux运维等知识,带你从懵懂少年走向人生巅峰,迎娶白富美!
关注微信公众号【 IT特靠谱 】,你将会发现新大陆!

List、Set和Map的区别

在这里插入图片描述
    开门见山,直接先上这副图。可见:List和Set是Collection的子类 ,而Map与List、Set和Collection没半毛钱关系!

1. List、Set和Map对比

List

(1)可以允许重复的对象;
(2)可以插入多个null元素;
(3)是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序;
(4)常用的实现类有ArrayList,LinkedList和Vector。ArrayList提供了使用索引的随意访问,底层结构是数组,优查询劣增删;而LinkedList经常用于添加或删除元素的场合,底层结构是链表。

Set

(1)不允许重复的对象;
(2) 无序容器,你无法保证每个元素的存储顺序。TreeSet通过Conparator或者Comparable维护了一个排序顺序;
(3)只允许一个null元素;
(4)Set常用的实现类是HashSet,LinkedHashSet以及TreeSet。最流行的是基于HashMap实现的;HashSet,TreeSet还实现了SortedSet接口,因此TreeSet是一个根据其compare()和compareTo()的进行排序的有序容器。

Map

(1)Map不是collection的子接口或者实现类,Map是一个接口;
(2)HashMap底层是数据+链表的组成,是无序的,通过hashCode()方法计算索引值后再存储或查找元素;链表长度大于8时转换成数组+红黑树结构;
在这里插入图片描述
(3)Map的每个Entry都持有俩个对象,一个键一个值,可能会持有相同的值对象但键对象必须是唯一的;
(4)TreeMap也通过Comparator或者Comparable维护了一个排序顺序;
(5)Map里你可以拥有任意个null的value值,但只能有一个null的key键;
(6)常用的实现类HashMap,LinkedHashMap,Hashtable,TreeMap。

2. 何时选择使用list,set或者map?

  • 如果经常使用索引来对元素进行访问,那么使用List,如果你已经知道索引了的话,那么List的实现类比如ArrayList可以提供更快速的访问;如果经常添加删除元素,那么选择LinkedList。
  • 如果想让容器中的元素能够按照他们插入的次序进行有序存储,那么还是List,因为List是一个有序容器。
  • 如果想要保证插入数据的唯一性,可以选择一个Set的实现类。
  • 如果你以键和值的形式进行数据存储那么Map是你正确的选择。

3. HashMap/HashSet的底层插入和查询原理

说明1:HashSet底层是HashMap实现的!
     hashSet.add(添加的对象)和hashMap.add(添加的对象)方法添加的对象必须保证如下3点规则,否则可能导致保存的对象重复:
(1)相同对象的hashCode()计算值相等;
(2)相同对象的equals()计算值相等;
(3)不同对象的hashCode()计算值可能相等,但是equals()计算值一定不相等!
在这里插入图片描述
在这里插入图片描述
说明2: HashMap底层是数组+链表或数组+红黑树数据结构
    HashMap底层是数组+链表或数组+红黑树数据结构,key键的hash值可以算出node的存储数组位置!如果多个node存放到相同数组位置,那么就通过链表的方式存储,如果链表长度大于8,自动转换成红黑树的存储结构。因此我们要尽量避免链表长度过长或红黑树,因为put和get的效率相对较低!

3.1 HashMap的put(“key”,“value”)方法底层分析
(1)首先根据key生成key键的hash值,根据一些列运算获取存放该键值对的数组的索引index;
(2)根据index从数组中定位到指定位置,如果指定位置已经存在值了,那么equals(key)计算key键是否相等,如果相等,那么用新的值覆盖旧的值;如果指定位置没有值,那么直接插入新值!
(3)如果不同的对象的key的hash值相同(称为hash碰撞或hash冲突),那么计算的索引也是一样的,那么在数组相同位置会存放2个或多个值,这时候链表结构解决了这个问题!

3.2 HashMap的get(“key”)方法底层分析
(1)首先根据key生成key键的hash值,根据一些列运算获取存放该键值对的数组的索引index;
(2)根据index从数组中定位到指定位置,如果指定位置没有值,那么返回的值为null;如果指定位置有值(无链表,有且只有一个值)那么直接返回该值;如果指定位置是链表,那么再根据key的equals(key)方法来获取链表中我们想要的那个值!

4. 总结:

    上面的put和get都是先比较key的hash值是否相同,再通过equals()方法比较key是否相同!所以当我们重写某个类的equals()方法的时候,切记一定要重写其hashCode()方法!
也就是说HashMap必须要保证:

  • 相同的key必须有相同的hashCode;
  • 相同的key必须equals()相等;
  • 不同的key可能有相同的hashCode,但是equals()必须不相等!!这也是我们常用String类型作为key的原因,因为String类的equals()方法和hashCode()方法满足上面的3点!!

猜你喜欢

转载自blog.csdn.net/IT_Most/article/details/108663811