当前位置:   article > 正文

【Java基础】详解集合类(List、Set、Map)_set list map

set list map

目录

流程图

常见的数据结构

数组结构

        概念

        优点:

        缺点:

链表结构

        概念

        优点:

        缺点:

哈希表结构

        概念

        为何随机增删查询效率都很高

 List

ArrayList

        概念

        常用方法

Vector

        概念

        常用方法

ArrayList和Vector的区别

        1.在线程同步的方面来讲

LinkedList

        概念

        常用方法

Set

HashSet

        概念

        常用方法

LinkedHashSet

        概念

        常用方法

HashSet和LinkedHashSet的区别

TreeSet

        概念

        常用方法

List和Set的区别

        1.是否有序

        2.是否重复

        3.null元素数量

        4.获取元素方式

Map

HashMap

        概念

        为什么长度为8转化为红黑树,不是一开始就是红黑树或者链表呢?

        常用方法

TreeMap

        概念

        常用方法

HashMap和TreeMap的区别

        1.排序方式不同

        2.线程安全性相同

        3.继承的父类不同

        4.底层数据结构不同

HashTable

        概念

HashMap和HashTable的区别

        1.继承的父类不同

        2.提供的接口不同

        3.对Null key和Null value的支持不同

        4.线程安全性不同

        5.初始容量大小和扩充容量大小不同

        6.计算hash值的方法不同


我们口中所说的集合类的类型主要为三种:set(集合),map(映射),list(列表)

集合类是通过两个接口来实现的

        1.Collection接口,list和set实现了这个接口

        2.Map接口,map实现了这个接口

大体有

图1

图2

自己根据源码总结的流程图为

流程图

常见的数据结构

我们常见的数据结构有三种

        1.数组结构

        2.链表结构

        3.哈希表结构

数组结构

        概念

                存储区间连续、内存占用严重、空间复杂度大、大小固定,不易扩展

        优点:

                随机读取和修改效率高,因为数组是连续的,随机访问性强,查找速度快

        缺点:

                插入和删除效率低,因为插入数据,这个位置后面的数据在内存中都要往后移动,且大小固定,不易动态扩展

链表结构

        概念

                存储区间离散、占用内存宽松、空间复杂度小、大小不固定,易于扩展

        优点:

                插入删除速度快,内存利用效率高,没有固定大小,扩展灵活

        缺点:

                查询较复杂,不能随机查找,每次都是从第一个开始遍历,查询效率低

哈希表结构

        概念

                结合数组结构和链表结构的优点,从而实现了查询修改效率高,插入和删除效率也高的一种数据结构

                HashMap就是这样一种数据结构

在这里插入图片描述

        为何随机增删查询效率都很高

                因为增删是在链表上进行的,查询是在数组上进行的

参考文章:

 HashMap底层实现原理解析_苟且偷生的程序员的博客-CSDN博客_hashmap底层实现原理

 List

List(列表)中,分为三大部分

        1. ArrayList

        2.Vector

        3.LinkedList

ArrayList

        概念

                底层数据结构为数组array,查询速度快,增删改慢,因为是一种类似数组的形式进行存储,所以随机访问的速度极快

        常用方法

  1. public class Test01 {
  2. public static void main(String[] args) {
  3. ArrayList<String> arrayList = new ArrayList<>(); //创建一个arrayList对象
  4. ArrayList<String> arrayList1 = new ArrayList<>(10); //创建一个长度为10的arrayList
  5. arrayList.add("123"); //向arrayList集合中添加一个元素,可以有选择的返回一个boolean类型
  6. boolean add = arrayList.add("456"); //返回boolean类型
  7. String s = arrayList.get(1); //返回下标为1的元素(下标从0开始)
  8. String set = arrayList.set(1, "789"); //将下标为i的元素替换为"789"并返回被替换的元素
  9. int size = arrayList.size(); //返回元素个数
  10. String remove1 = arrayList.remove(0); //删除下标为0的元素(下标从0开始),返回被删除的元素
  11. boolean remove = arrayList.remove("123"); //删除集合中第一次出现的指定元素,返回boolean类型
  12. ArrayList<Integer> integerArrayList = new ArrayList<>();
  13. ArrayList<Integer> integerArrayList1 = new ArrayList<>();
  14. integerArrayList.add(123);
  15. integerArrayList.add(123);
  16. integerArrayList.add(456);
  17. integerArrayList1.add(123);
  18. System.out.println(integerArrayList);
  19. integerArrayList.removeAll(integerArrayList1); //从集合integerArrayList中删除integerArrayList1的所有元素,不是只删除第一个,是删除所有的
  20. System.out.println(integerArrayList);
  21. arrayList.clear(); //清除集合中的元素
  22. boolean empty = arrayList.isEmpty(); //判断集合是否为空
  23. boolean contains = arrayList.contains("123"); //判断集合中是否有“123”这个元素,返回boolean类型
  24. arrayList.add("123");
  25. arrayList.add("456");
  26. Iterator<String> iterator = arrayList.iterator(); //返回集合首地址的迭代器,迭代器指向的是下标为0的前一个地址(?)
  27. boolean b = iterator.hasNext(); //判断iterator是否存在下一个元素,返回boolean
  28. String next = iterator.next(); //先将指针移动到下一个位置,然后再获取值
  29. while(iterator.hasNext()) {
  30. System.out.println(iterator.next());
  31. }
  32. }
  33. }

这里需要注意,迭代器iterator返回的是ArrayList下标为0的元素地址的前一个

Vector

        概念

                底层的数据结构是是数组array,与ArrayList相同,查询速度快,增删改慢

        常用方法

  1. public class Test01 {
  2. public static void main(String[] args) {
  3. Vector<String> Vector = new Vector<>(); //创建一个Vector对象
  4. Vector<String> Vector1 = new Vector<>(10); //创建一个长度为10的Vector
  5. Vector.add("123"); //向Vector集合中添加一个元素,可以有选择的返回一个boolean类型
  6. boolean add = Vector.add("456"); //返回boolean类型
  7. String s = Vector.get(1); //返回下标为1的元素(下标从0开始)
  8. String set = Vector.set(1, "789"); //将下标为i的元素替换为"789"并返回被替换的元素
  9. int size = Vector.size(); //返回元素个数
  10. String remove1 = Vector.remove(0); //删除下标为0的元素(下标从0开始),返回被删除的元素
  11. boolean remove = Vector.remove("123"); //删除集合中第一次出现的指定元素,返回boolean类型
  12. Vector.clear(); //清除集合中的元素
  13. boolean empty = Vector.isEmpty(); //判断集合是否为空
  14. boolean contains = Vector.contains("123"); //判断集合中是否有“123”这个元素,返回boolean类型
  15. Vector.add("123");
  16. Vector.add("456");
  17. Iterator<String> iterator = Vector.iterator(); //返回集合首地址的迭代器,迭代器指向的是下标为0的前一个地址(?)
  18. boolean b = iterator.hasNext(); //判断iterator是否存在下一个元素,返回boolean
  19. String next = iterator.next(); //先将指针移动到下一个位置,然后再获取值
  20. while(iterator.hasNext()) {
  21. System.out.println(iterator.next());
  22. }
  23. }
  24. }

        与ArrayList相同

ArrayList和Vector的区别

        1.在线程同步的方面来讲

                ArrayList线程不同步,Vector线程安全,因为每个方法上都加上了synchronized,但是Vector的效率小于ArrayList

                Vector安全但是效率低,因为加锁和放锁的过程中,在系统中是有开销的

        ArrayList

 无synchronized

        Vectoer

 有synchronize

LinkedList

        概念

                底层数据接口使用链表,增删改速度快,查询稍慢

                LinkedList是一个双向链表,没有初始化大小,也没有扩容的机制,就是一直在前面或者后面新增就好。

        常用方法

  1. public class Test01 {
  2. public static void main(String[] args) {
  3. LinkedList<String> LinkedList = new LinkedList<>(); //创建一个LinkedList对象,无法初始化大小
  4. LinkedList.add("123"); //向LinkedList链表中添加一个元素,可以有选择的返回一个boolean类型
  5. boolean add = LinkedList.add("456"); //返回boolean类型
  6. LinkedList.addFirst("123"); //在头部插入
  7. LinkedList.addLast("123"); //在尾部插入
  8. String s = LinkedList.get(1); //返回下标为1的元素(下标从0开始)
  9. String first = LinkedList.getFirst(); //获取第一个下标的元素
  10. String last = LinkedList.getLast(); //获取最后一个下标的元素
  11. String set = LinkedList.set(1, "789"); //将下标为i的元素替换为"789"并返回被替换的元素
  12. int size = LinkedList.size(); //返回元素个数
  13. String remove1 = LinkedList.remove(0); //删除下标为0的元素(下标从0开始),返回被删除的元素
  14. boolean remove = LinkedList.remove("123"); //删除链表中第一次出现的指定元素,返回boolean类型
  15. String s1 = LinkedList.removeFirst(); //删除链表中的第一个元素
  16. String s2 = LinkedList.removeLast(); //删除链表的最后一个元素
  17. boolean b1 = LinkedList.removeFirstOccurrence("123"); //删除链表中第一次出现"123"所在位置的元素
  18. boolean b2 = LinkedList.removeLastOccurrence("123"); //删除链表中最后一次出现"123"所在位置的元素
  19. LinkedList.clear(); //清除链表中的元素
  20. boolean empty = LinkedList.isEmpty(); //判断链表是否为空
  21. boolean contains = LinkedList.contains("123"); //判断链表中是否有“123”这个元素,返回boolean类型
  22. LinkedList.add("123");
  23. LinkedList.add("456");
  24. Iterator<String> iterator = LinkedList.iterator(); //返回链表首地址的迭代器,迭代器指向的是下标为0的前一个地址(?)
  25. boolean b = iterator.hasNext(); //判断iterator是否存在下一个元素,返回boolean
  26. String next = iterator.next(); //先将指针移动到下一个位置,然后再获取值
  27. while(iterator.hasNext()) {
  28. System.out.println(iterator.next());
  29. }
  30. }
  31. }

Set

Set接口有三个主要的实现类

        1.HashSet

        2.LinkedHashSet

        3.TreeSet

set的实现类(HashSet,LinkedHashSet,TreeSet)都是线程不安全的, 解决方法

  1. class E{
  2. public static void main(String[] args) {
  3. Set<Integer> set = new HashSet<>();
  4. Set<Integer> integers = Collections.synchronizedSet(set); //这里是Collections,不是Collection,一个是类,一个是接口
  5. }
  6. }

HashSet

        概念

                 Set最常用的实现类,底层数据结构运用Hash(散列/哈希)算法,底层也是用数组实现

        常用方法

  1. public class Test02 {
  2. public static void main(String[] args) {
  3. HashSet<String> HashSet = new HashSet<>(); //创建一个HashSet对象,无法初始化大小
  4. HashSet.add("123"); //向HashSet链表中添加一个元素,可以有选择的返回一个boolean类型
  5. boolean add = HashSet.add("456"); //返回boolean类型
  6. int size = HashSet.size(); //返回元素个数
  7. boolean remove1 = HashSet.remove(0); //删除下标为0的元素(下标从0开始),返回被删除的元素
  8. boolean remove = HashSet.remove("123"); //删除链表中第一次出现的指定元素,返回boolean类型
  9. HashSet.clear(); //清除链表中的元素
  10. boolean empty = HashSet.isEmpty(); //判断链表是否为空
  11. boolean contains = HashSet.contains("123"); //判断链表中是否有“123”这个元素,返回boolean类型
  12. HashSet.add("123");
  13. HashSet.add("456");
  14. Iterator<String> iterator = HashSet.iterator(); //返回链表首地址的迭代器,迭代器指向的是下标为0的前一个地址(?)
  15. boolean b = iterator.hasNext(); //判断iterator是否存在下一个元素,返回boolean
  16. String next = iterator.next(); //先将指针移动到下一个位置,然后再获取值
  17. while(iterator.hasNext()) { //迭代器遍历
  18. System.out.println(iterator.next());
  19. }
  20. for (String str: HashSet) { //for循环遍历
  21. System.out.println(str);
  22. }
  23. }
  24. }

LinkedHashSet

        概念

                继承和HashSet类,底层也是哈希表结构,但是为了保持数据先后添加的顺序,所以又加了链表结构,因为多加了一层数据结构,所以效率低,不建议使用

        常用方法

  1. public class Test02 {
  2. public static void main(String[] args) {
  3. LinkedHashSet<String> LinkedHashSet = new LinkedHashSet<>(); //创建一个LinkedHashSet对象,无法初始化大小
  4. LinkedHashSet.add("123"); //向LinkedHashSet链表中添加一个元素,可以有选择的返回一个boolean类型
  5. boolean add = LinkedHashSet.add("456"); //返回boolean类型
  6. int size = LinkedHashSet.size(); //返回元素个数
  7. boolean remove1 = LinkedHashSet.remove(0); //删除下标为0的元素(下标从0开始),返回被删除的元素
  8. boolean remove = LinkedHashSet.remove("123"); //删除链表中第一次出现的指定元素,返回boolean类型
  9. LinkedHashSet.clear(); //清除链表中的元素
  10. boolean empty = LinkedHashSet.isEmpty(); //判断链表是否为空
  11. boolean contains = LinkedHashSet.contains("123"); //判断链表中是否有“123”这个元素,返回boolean类型
  12. LinkedHashSet.add("123");
  13. LinkedHashSet.add("456");
  14. Iterator<String> iterator = LinkedHashSet.iterator(); //返回链表首地址的迭代器,迭代器指向的是下标为0的前一个地址(?)
  15. boolean b = iterator.hasNext(); //判断iterator是否存在下一个元素,返回boolean
  16. String next = iterator.next(); //先将指针移动到下一个位置,然后再获取值
  17. while(iterator.hasNext()) { //迭代器遍历
  18. System.out.println(iterator.next());
  19. }
  20. for (String str: LinkedHashSet) { //for循环遍历
  21. System.out.println(str);
  22. }
  23. }
  24. }

HashSet和LinkedHashSet的区别

        1.在HashSet插入中,不保留顺序,这意味着元素的插入顺序不需要与元素的检索顺序相同。

           在LinkedHashSet中,保留插入顺序,这意味着元素的插入顺序必须与元素的检索顺序相同。

        2.HashSet的效率高于LinkedHashSet

TreeSet

        概念

                Set接口的实现类,实现了SortSet接口,底层采用红黑树算法,TreeSet只能存储相同类型的对象的引用

        常用方法

  1. public class Test02 {
  2. public static void main(String[] args) {
  3. TreeSet<String> TreeSet = new TreeSet<>(); //创建一个TreeSet对象,无法初始化大小
  4. TreeSet.add("123"); //向TreeSet链表中添加一个元素,可以有选择的返回一个boolean类型
  5. boolean add = TreeSet.add("456"); //返回boolean类型
  6. int size = TreeSet.size(); //返回元素个数
  7. boolean remove1 = TreeSet.remove(0); //删除下标为0的元素(下标从0开始),返回被删除的元素
  8. boolean remove = TreeSet.remove("123"); //删除链表中第一次出现的指定元素,返回boolean类型
  9. TreeSet.clear(); //清除链表中的元素
  10. boolean empty = TreeSet.isEmpty(); //判断链表是否为空
  11. boolean contains = TreeSet.contains("123"); //判断链表中是否有“123”这个元素,返回boolean类型
  12. TreeSet.add("123");
  13. TreeSet.add("456");
  14. Iterator<String> iterator = TreeSet.iterator(); //返回链表首地址的迭代器,迭代器指向的是下标为0的前一个地址(?)
  15. boolean b = iterator.hasNext(); //判断iterator是否存在下一个元素,返回boolean
  16. String next = iterator.next(); //先将指针移动到下一个位置,然后再获取值
  17. while(iterator.hasNext()) { //迭代器遍历
  18. System.out.println(iterator.next());
  19. }
  20. for (String str: TreeSet) { //for循环遍历
  21. System.out.println(str);
  22. }
  23. }
  24. }

List和Set的区别

 对于ArrayList和HashSet来说

        1.是否有序

                ArrayList是有序的

                HashSet是无序的

        2.是否重复

                ArrayList是可重复的

                HashSet是不可重复的

        3.null元素数量

                ArrayList可以有多个null元素

                HashSet只能有一个null元素

        4.获取元素方式

                ArrayList可以使用迭代器取出所有元素,也可以通过get(index)获取制定下表的元素

                Set只能通过迭代器获得所有元素,然后逐个遍历

Map

 Map接口有三个主要的实现类

        1.HashMap

        2.TreeMap

        3.HashTable

HashMap

        概念

                哈希表的实现原理,先拿一个数组表示位桶,每个位桶在用链表存储数据,当数据超过阈值8,且数组长度超过64的时候,会将数据转化为红黑树来存储数据,当数据个数小于6的时候,红黑树会退化为链表

                所以HashMap底层的数据结构是数组+链表+红黑树

        为什么长度为8转化为红黑树,不是一开始就是红黑树或者链表呢?

        首先我们知道,链表的平均查找的时间复杂度是O(n),红黑树有和链表不一样的查找性能,由于红黑树有自平衡的特点,所以始终可以将查找的时间复杂度控制在O(logn)

        至于为什么不一开始就是用红黑树,是因为

                对于红黑树来说,虽然查询成本低,但是新增的成本高

                对于链表来说,虽然查询成本高,但是新增的成本低

        最初链表还不是很长,所以O(n)和O(logn)的区别不大,如果长度过长,这种区别就回有多体现所以为了提高查找性能,要把链表转化为红黑树

        常用方法

  1. public class Test03 {
  2. public static void main(String[] args) {
  3. HashMap<String, Integer> hashMap = new HashMap(); //新建一个HashMap
  4. hashMap.put("123",1); //将值存放到HashMap中
  5. Integer integer = hashMap.get("123"); //根据键获取值
  6. int size = hashMap.size(); //获取HashMap大小
  7. hashMap.clear(); //清空HashMap
  8. boolean empty = hashMap.isEmpty(); //判断是否为空
  9. Integer remove = hashMap.remove("123"); //根据键删除值,并返回
  10. Collection<Integer> collection;
  11. collection = hashMap.values(); //以Collection的形式返回HashMap集合中所有value组成的值
  12. System.out.println(collection);
  13. Set<String> strings = hashMap.keySet(); //Set的形式返回键的集合
  14. Iterator<String> iterator1 = strings.iterator(); //与keySet合用,获得迭代器
  15. Set<Map.Entry<String, Integer>> entries = hashMap.entrySet(); //将HashMap中的每个键值转化为Entry对象并返回Set集合
  16. Iterator<Map.Entry<String, Integer>> iterator = entries.iterator(); //与entrySet合用,返回迭代器
  17. while(iterator.hasNext()){
  18. Map.Entry<String, Integer> next = iterator.next();
  19. System.out.println(next.getKey()); //获得键
  20. System.out.println(next.getValue()); //获得值
  21. }
  22. }
  23. }

TreeMap

        概念

                实现了SortedMap接口,是一个有序的集合,底层是红黑树结构,每一个key-value都作为一个红黑树的节点

        常用方法

  1. public class Test03 {
  2. public static void main(String[] args) {
  3. TreeMap<String, Integer> TreeMap = new TreeMap(); //新建一个TreeMap
  4. TreeMap.put("123",1); //将值存放到TreeMap中
  5. Integer integer = TreeMap.get("123"); //根据键获取值
  6. int size = TreeMap.size(); //获取TreeMap大小
  7. TreeMap.clear(); //清空TreeMap
  8. boolean empty = TreeMap.isEmpty(); //判断是否为空
  9. Integer remove = TreeMap.remove("123"); //根据键删除值,并返回
  10. Collection<Integer> collection;
  11. collection = TreeMap.values(); //以Collection的形式返回TreeMap集合中所有value组成的值
  12. System.out.println(collection);
  13. Set<String> strings = TreeMap.keySet(); //Set的形式返回键的集合
  14. Iterator<String> iterator1 = strings.iterator(); //与keySet合用,获得迭代器
  15. Set<Map.Entry<String, Integer>> entries = TreeMap.entrySet(); //将TreeMap中的每个键值转化为Entry对象并返回Set集合
  16. Iterator<Map.Entry<String, Integer>> iterator = entries.iterator(); //与entrySet合用,返回迭代器
  17. while(iterator.hasNext()){
  18. Map.Entry<String, Integer> next = iterator.next();
  19. System.out.println(next.getKey()); //获得键
  20. System.out.println(next.getValue()); //获得值
  21. }
  22. }
  23. }

HashMap和TreeMap的区别

        1.排序方式不同

                HashMap是通过hashcode对内容进行快速查找的,HashMap中的元素是没有顺序

                TreeMap所有元素是由某一固定顺序的,如果需要的到一个有序结构,就应该使用TreeMap

        2.线程安全性相同

                HashMap和TreeMap都是线程不安全

        3.继承的父类不同

                HashMap继承AbstractMap类,覆盖了hashcode和equals方法

                ThreeMap继承SortedMap类,保持键的有序顺序

        4.底层数据结构不同

                HashMap基于hash表实现,底层数据结构为数组+链表+红黑树

                TreeMap基于红黑树实现,底层数据结构为红黑树

HashTable

        概念

                继承了Map接口,和HashMap类似

HashMap和HashTable的区别

        1.继承的父类不同

                HashMap继承AbstractMap

                Hashtable继承Dicitionary(已废弃?)

        2.提供的接口不同

                HashTable比HashMap多提供elments和contians方法

        3.对Null key和Null value的支持不同

                HashTable既不支持Null key也不支持Null value

                HashMap中,Null可以作为key,这样的键只有一个

        4.线程安全性不同

                HashTable线程安全,但是效率低

                HashMap线程不安全,但是效率高

        5.初始容量大小和扩充容量大小不同

                HashTable默认初始化大小为11,每次扩充容量变为原来的2n+1

                HashMap默认初始化大小为16,每次扩充容量变为2倍

        6.计算hash值的方法不同

                HashTable直接使用对象的hashCode,计算时需要进行除法运算

                HashMap为了提高计算效率,将哈希表的大小固定为2的幂,不用做除法,只需要位运算即可

                HashMap虽然效率高,但是Hash冲突也增加了

参考文章

HashMap 与HashTable的区别_wangxing233的博客-CSDN博客_hashmap和hashtable的区别

java各种集合类区别_小白新人-CSDN博客_java集合类

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/973916
推荐阅读