Java集合

集合


什么是集合:

集合就是一个容器,它提供了一种存储空间可变的存储模型,存储的容量随着需求动态的分配空间;

数组与集合区别:

  • 数组长度不可以发生改变,一经定义长度就固定了;集合的长度可以发生改变,动态的分配存储空间;
  • 数组中既可以存储基本数据类型也可以存储引用数据类型;而集合中只能存储引用数据类型;

集合的分类:
在这里插入图片描述



Collection集合


概述:

Collection集合是单列集合的顶层接口,其子接口有List、Set;


Collection集合的常用方法:

常用方法方法说明
boolean add(E e)在集合末尾添加元素
boolean remove(Object o)从集合中删除指定的元素
boolean contains(Object o)查看集合中是否包含指定的元素
int size()查看集合中数组的个数

补充: (☆☆☆☆☆)

  • 判空:判断集合是否为空

    • 有两层含义:一个是集合为null,另一层为集合中的元素个数为0;

      if(list != null && list.size() > 0) 
      
    • 原因:这里的判空运用到了短路逻辑与,首先判断我们的集合是否为空对象,如果是空对象那么就不再去判断集合的长度;如果集合对象不为空,那么就去验证集合中是否存在元素,如果集合长度大于0,则说明集合不为空;

    • 为什么要先对集合对象进行判空,而不是先对集合的长度进行判断呢?

      答:如果先判断集合的长度是否大于0,假如此时集合对象为空,没有被实例化,那么你通过集合对象去调用size方法就会报空指针异常;


迭代器

什么是迭代器:

迭代器是一个接口,是用来实现对集合的遍历;它拥有一个游标,可以指向集合中的下一个元素;

为什么需要它?

答:因为并不是每个Collection集合的子级都有索引,但是集合都需要进行遍历,为了解决这一问题就有了迭代器,每个子级都需要实现迭代器接口以及重写其中的hashNext()next()方法;hashNext()方法用来判断集合中是否还有元素,next()是指向下一个元素的指针;


迭代器的使用步骤:

  • 获取迭代器对象;

  • 判断是否有下一个元素;

  • 循环获取每一个元素;

  • 代码示例:

    // 获取迭代器对象
    Iterator<Student> iter = list.iterator();
    while(iter.hashNext()) { // 判断是否还有下一个元素,遍历集合
        System.out.println(iter.next()); // 将迭代器指针移动到下一个元素
    }
    

并发修改异常: (☆☆☆)

  • 产生条件:(二者必须同时满足)

    • 并发:至少两个对象在同一时间段对同一个集合进行操作;
    • 修改:在并发期间,发生了修改集合元素的操作;
  • 代码示例:

    // 获取迭代器对象
    Iterator<Student> iter = list.iterator();
    while(iter.hashNext()) { // 判断是否还有下一个元素,遍历集合
        list.add(new Student()); // 抛出ConcurrentModificationException
        System.out.println(iter.next()); // 将迭代器指针移动到下一个元素
    }
    
  • 说明:通过迭代器对集合的遍历使用的是迭代器对象进行操作的,但是在遍历过程中,却用了集合对象对集合元素进行了添加操作,这就符合了并发修改异常的产生条件,在循环这一时间段内,迭代器对象和集合对象同时对集合进行了操作,并且集合对象修改了我们的集合元素,所以抛出异常;



List集合


List集合的概述和特点:

  • 概述:List集合是Collection集合的子接口,Collection集合中的方法List都有,除此之外List集合还自己特有的方法,即根据索引来进行操作的方法;
  • 特点:List集合是有序的、元素可以重复的集合;

List集合中的特有方法:

方法方法说明
void add(int index, E element)在集合中指定的位置插入给定的元素
E remove(int index)删除集合中指定索引位置处的元素
E set(int index,E element)将集合中指定索引位置处的元素修改为给定的元素值,并返回被修改的元素
E get(int index)返回集合中指定索引位置处的元素

删除集合中指定的元素: (☆☆☆)

  • 借助新集合删除:时间复杂度O(n),空间复杂度O(m)

    List<String> list = new ArrayList<>();
    list.add("张三");
    list.add("李四");
    list.add("王五");
    list.add("张三");
    // 创建新的集合
    List<String> result = new ArrayList<>();
    for(int i = 0; i < list.size(); i++) {
        String str = list.get(i);
        if(!str.equals("张三")) { 	// 只添加不是张三的元素
            result.add(str);
        }
    }
    list = result;
    

  • 在原有集合中删除:时间复杂度O(n),空间复杂度O(1);(常用)

    (面试题:如何删除集合中的指定元素,答案:反向遍历);

    // 通过反向遍历整个集合来删除
    for(int i = list.size() - 1; i >= 0; i--) {
        String str = list.get(i);
        if(str.equals("张三")) {
            list.remove(i);
        }
    }
    

ArrayList集合与LinkedList集合

概述:

ArrayList集合与LinkedList集合是List集合的子集,拥有List中的所有方法;


ArrayList、LinkedList与Vector的区别: (☆☆☆)

  • ArrayList底层是用数组实现,增删效率低、查询效率高,线程不安全,效率高;
  • LinkedList底层是用双向链表实现的,增删效率高、查询效率低,线程不安全,效率高;
  • Vector底层是用数组实现的,增删效率低、查询效率高,线程安全,效率低;

代码示例:

// LinkedList集合的操作与ArrayList一致,自行实践
public class Demo {
    public static void main(String[] args) {
        // 创建集合对象
        List<String> list = new ArrayList<>();
        // 添加元素
        for(int i = 0; i < 4; i++) {
            list.add("aa" + i);
        }
        // 插入元素
        list.add(1, "cc");
        // 打印集合
        System.out.println(list);
        // 删除指定位置元素
        list.remove(0);
        System.out.println(list);
        // 修改集合元素
        list.set(0, "dd");
        System.out.println(list);
    }
}
运行结果:
    [aa0, cc, aa1, aa2, aa3]
    [cc, aa1, aa2, aa3]
    [dd, aa1, aa2, aa3]


Set集合


概述和特点:

Set集合是Collection结合的子集,Collection中的方法Set集合都有;

特点:

  • Set集合中的元素唯一,没有重复元素;
  • 元素存储无序;
  • 没有索引;

HashSet集合

概述:

和set的特点一样,底层是用哈希表实现的(数组 + 链表);


哈希表的原理: (☆☆☆)

先对key进行操作获取哈希值,再去位桶数组中去比较是否有此哈希值,如果没有直接将该元素值存储在对应的哈希值位置,如果已经有了该哈希值,那么就去该哈希值对应的链表中去比较是否有相同的元素,如果元素值重复就覆盖它,如果没有重复就在链表的末尾加入该元素值;


HashSet元素唯一的原因:

HashSet底层使用HashMap来实现的,其唯一性是利用了HashMap的key键唯一来保证的;即,HashSet利用HashMap的key键来存储Set集合中的元素;

其本质是依赖了hashCodeequals方法:

  先计算其哈希值,然后和位桶数组中的哈希值进行比较,如果没有相同的哈希值,则直接加入到对应的哈希值位置处,如果重复了,与哈希值对应的链表中的元素进行比较,如果没有重复就加入到链表中,如果重复了,就覆盖它;


LinkedHashSet集合

概述和特点:

  • 概述:底层用哈希表和链表实现;

  • 特点:元素唯一;存取有序;其具备了List集合和Set集合的特点;

  • 应用场景: 去重;(☆☆)


代码示例:

public class Demo{
    public static void main(String[] args) {
        LinkedHashSet<String> list = new LinkedHashSet<>();
        list.add("张三");
        list.add("李四");
        list.add("张三");
        list.add("王五");
        list.add("赵六");
        System.out.println(list);
    }
}
运行结果:
    [张三, 李四, 王五, 赵六]

TreeSet集合

特点:

  • 元素唯一性;
  • 元素有序(按照一定规则排序);
  • 没有索引;

排序方式: (☆☆☆)

  • 自然排序:

    • 要求:

      1. 创建TreeSet集合的时候,使用无参构造方法;
      2. 创建TreeSet集合时的泛型类必须实现Comparable接口,重写compareTo()方法;
    • 比较器的存储规则:底层是用二叉树实现的;

      1. 如果添加的是第一个元素,就会作为根节点;
      2. 从第二个元素开始:
        1. 根据你给的的compareTo方法的返回值来处理:
          1. 正数:放在节点的右边;
          2. 负数:放在节点的左边;
          3. 0:覆盖元素;
    • 代码示例:

      public class Student implements Comparable<Student> {
          
          // 类的组成部分省略
          
          @Override
          public int compareTo(Student s) {
              // 按照年龄从小到大排序
              int num = this.age - s.age;
              // 年龄相同时按照姓名的字母排序
              return num == 0 ? this.name.compareTo(s.name) : num;
          }
      } 
      public class Demo02{
          public static void main(String[] args) {
              TreeSet<Student> set = new TreeSet<>();
              
              Student s1 = new Student("张三", 13);
              Student s2 = new Student("李四", 14);
              Student s3 = new Student("王五", 13);
              Student s4 = new Student("赵六", 15);
      
              set.add(s1);
              set.add(s2);
              set.add(s3);
              set.add(s4);
      
              System.out.println(set);
          }
      }
      

  • 比较器排序: 实现Comparator接口重写compare方法

    一般以内部类的方式实现该接口,也可以通过创建实现类并将实现类对象传入的方式;

    public class Demo03 {
        public static void main(String[] args) {
            TreeSet<Student> set = new TreeSet<Student>(new Comparator<Student>() {
                @Override
                public int compare(Student s1, Student s2) {
                    int num = s1.getAge() - s2.getAge();
                    return num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                }
            });
    
            Student s1 = new Student("张三", 13);
            Student s2 = new Student("李四", 14);
            Student s3 = new Student("王五", 13);
            Student s4 = new Student("赵六", 15);
    
            set.add(s1);
            set.add(s2);
            set.add(s3);
            set.add(s4);
    
            System.out.println(set);
        }
    }
    

  • 两种排序方式如何选择?

    答:选择比较器排序,因为如果我们使用了API自动帮我们重写的compareTo方法,默认就会按照字典顺序进行排序,如果此时的排序规则并不是我们想要的,那么我们就不能改变其功能,而我们使用比较器排序,无论如何是我们自己定制的规则,可以根据自己的需求来定制我们想要的功能;



Map集合


Map集合的概述:

Map集合底层采用哈希表来实现的,它是双列集合,实现类有HashTableHashMapTreeMap


Map集合的特点:

  • 键值对映射关系,一个键对应一个值;
  • 键不能重复,允许有唯一一个键为null,值可以重复,值可以有多个为null;
  • 元素存取无序;
  • map集合中没有迭代器的概念;

常用方法:

方法方法说明
V put(K key,V value)向集合中添加元素
V remove(Object key)根据key来删除集合元素
boolean containsKey(Object key)判断是否包含指定的key
boolean containsValue(Object value)判断是否包含指定的value
int size()获取集合的长度
V get(Object key)根据key来获取value
Set keySet()获取所有key的集合
Collection values()获取所有的value集合
Set<Map.Entry<K,V>> entrySet()获取所有键值对对象的集合

Map集合的遍历:(☆☆☆☆☆)

  • 方式一:

    public class Demo04 {
        public static void main(String[] args) {
            HashMap<Integer, String> map = new HashMap<>();
            map.put(1, "aa");
            map.put(2, "bb");
            map.put(3, "cc");
            map.put(4, "dd");
    		// 先获取所有的key键,然后遍历key键去获取对应的value
            Set<Integer> keys = map.keySet();
            for (Integer key : keys) {
                String value = map.get(key);
                System.out.println(key + " : " + value);
            }
        }
    }
    

  • 方式二:

// 将所有的键值对取出,通过遍历逐一取出
Set<Map.Entry<Integer, String>> entries = map.entrySet();
    for (Map.Entry<Integer, String> entry : entries) {
        System.out.println(entry.getKey() + " : " + entry.getValue());
}

  • 两种方式的比较:(☆☆☆)
    1. 方式一:通过获取所有的key键,然后遍历所有的key键利用key键去找到相应的value值,其时间复杂度为O(n²),因为每次用key去获取value的时候,都需要遍历整个集合来进行匹配,直到找到我们所需要的value为止;
    2. 方式二:将所有的键值对都取出,然后单独取出每一个键值对,时间复杂度为O(n);所以方法二的更高;

HashMap集合

概述:

HashMap是Map接口的直接子类,其底层是用哈希表实现的,其key键唯一不可以重复;

存入HashMap集合中的元素没有顺序,因为其每次存入的位置是根据key键的哈希值来存入的;


HashMap与HashTable的区别:

HashMap与HashTable在使用方法上没有区别;

  • HashTable中的方法加了同步锁,线程安全,效率低;HashMap中的方法没有加同步锁,线程不安全,效率高;
  • HashTable不允许key和value为null;HashMap中允许key有唯一一个null,value可以有多个null;

代码示例:

public class Demo01 {
    public static void main(String[] args) {
        // 创建集合对象
        HashMap<String, String> map = new HashMap<>();
        // 添加元素
        map.put("001", "aa");
        map.put("002", "bb");
        map.put("003", "cc");
        map.put("004", "dd");
        // 遍历集合元素
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.println(entry.getKey() + " : " + entry.getValue());
        }
    }
}
运行结果:
    001 : aa
    002 : bb
    003 : cc
    004 : dd

TreeMap集合

HashMap与TreeMap的区别:

  1. HashMap是基于Hash表的结构,根据键的hashCode存储数据,TreeMap是基于红黑二叉树的结构

    2.HashMap是无序的,TreepMap实现了SortMap<K,V>接口,对key进行了排序

    3.HashMap允许有空键和空值,TreeMap不允许有空键和空值


代码示例:

public class Demo02 {
    public static void main(String[] args) {
        // 创建集合对象
        TreeMap<String, String> map = new TreeMap<>();
        // 添加元素
        map.put("001", "aa");
        map.put("002", "bb");
        map.put("003", "cc");
        map.put("004", "dd");
        // 遍历集合元素
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            System.out.println(entry.getKey() + " : " + entry.getValue());
        }
    }
}
运行结果:
    001 : aa
    002 : bb
    003 : cc
    004 : dd


集合的遍历



List集合的遍历

初始化集合:

class Dmeo01{
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        // 添加元素
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");
        list.add("ee");
    }
}

普通for循环遍历:

public static void forEach01() {
    for(int i = 0; i < list.size(); i++) {
        System.out.print(list.get(i) + "\t");
    }
}

迭代器遍历:

public static void forEach02() {
   Iterator<String> iter = list.iterator();
    while (iter.hasNext()) {
        System.out.print(iter.next() + "\t");
    } 
}

增强for循环遍历: (如果在遍历时不对集合元素进行修改,推荐此种方式遍历List集合)

public static void forEach03() {
    for (String str : list) {
        System.out.print(str + "\t");
    }
}

Set集合的遍历

集合的初始化:

public class Demo02 {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        for (int i = 0; i < 5; i++) {
            set.add("aa" + i);
        }
    }
}

迭代器遍历:

public static void forEach01() {
    Iterator<String> iter = set.iterator();
    while (iter.hasNext()) {
        System.out.print(iter.next() + "\t");
    }
}

增强for循环遍历:

public static void forEach02() {
   for (String str : set) {
        System.out.print(str + "\t");
    } 
}

Map集合的遍历

集合的初始化:

public class Demo04 {
    public static void main(String[] args) {
        HashMap<Integer, String> map = new HashMap<>();
        map.put(1, "aa");
        map.put(2, "bb");
        map.put(3, "cc");
        map.put(4, "dd");
    }
}

方式一:

public static void forEach01() {
    // 先获取所有的key键,然后遍历key键去获取对应的value
    Set<Integer> keys = map.keySet();
    for (Integer key : keys) {
        String value = map.get(key);
        System.out.println(key + " : " + value);
    }
}

方式二:

public static void forEach02() {
    // 将所有的键值对取出,通过遍历逐一取出
    Set<Map.Entry<Integer, String>> entries = map.entrySet();
        for (Map.Entry<Integer, String> entry : entries) {
            System.out.println(entry.getKey() + " : " + entry.getValue());
    }
}


Collections工具类


概述:

Collections集合工具类封装了很多种对集合进行操作的方法;类似于对数组进行操作的Arrays工具类;


常用方法:

方法名说明
public static void sort(List list)将指定的列表按升序排序
public static void reverse(List<?> list)反转指定列表中元素的顺序
public static void shuffle(List<?> list)使用默认的随机源随机排列指定的列表

代码示例:

public class Demo02 {
    public static void main(String[] args) {
        // 创建集合对象
        ArrayList<Integer> list = new ArrayList<>();

        list.add(13);
        list.add(11);
        list.add(9);
        list.add(20);
        list.add(16);

        // 将集合中的元素进行升序排列
        Collections.sort(list);
        System.out.println(list);

        //将排序后的集合反转
        Collections.reverse(list);
        System.out.println(list);

        // 将集合中的元素的顺序打乱
        Collections.shuffle(list);
        System.out.println(list);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值