• Java集合之单列集合


    • 什么是集合

    集合、数组都是对多个数据进行存储操作的结构,简称Java容器。
    说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库中)

    • 集合和数组的区别

    数组在存储多个数据方面的特点

    > 一旦初始化以后,其长度就确定了。
    > 数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。比如:String[] arr;int[] arr1;Object[] arr2;只能存储对于定义的类型元素

    数组在存储多个数据方面的缺点(集合可以很好的解决)

    > 一旦初始化以后,其长度就不可修改。
    > 数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
    > 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
    > 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。

    总结

    >数组是固定长度的;集合可变长度的。
    >数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
    >数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型(其实集合一般存储的数据也是同一类型的)。

    • 集合框架(常用集合类)

    Collection 单列集合,用来存储一个一个的对象
    |——- List 接口:元素按进入先后有序保存,可重复(”动态“数组)
    |—————- LinkedList 接口实现类, 底层是链表实现的,增和删比较快,查找和修改比较慢,没有同步, 线程不安全
    |—————- ArrayList 接口实现类, 底层是数组实现的, 随机访问,查找和修改快,增和删比较慢, 没有同步,线程不安全
    |—————- Vector 接口实现类 底层是数组实现的,同步,线程安全
    |———————- Stack 是Vector类的实现类
    |——- Set接口:存储无序的、不可重复的数据   -->高中讲的“集合”
    |—————- HashSet 使用hash表(数组)存储元素
    |————————- LinkedHashSet 链表维护元素的插入次序,可以保证存储的元素唯一
    |—————-TreeSet 底层是二叉树算法实现,元素排好序

    Map接口:双列集合,用来存储一对(key - value)一对的数据   -->高中函数:y = f(x)
    |———- Hashtable 接口实现类, 同步, 线程安全
    |———- HashMap 接口实现类 ,没有同步, 线程不安全-
    |—————–- LinkedHashMap 双向链表和哈希表实现
    |—————–- WeakHashMap
    |——–- TreeMap 红黑树对所有的key进行排序
    |———- IdentifyHashMap

    • Collection接口中的方法的使用

    在集合末尾添加元素——boolean add(E e)

    1. @Test
    2. public void test1(){
    3. Collection coll = new ArrayList();
    4. coll.add("aaa");
    5. coll.add(123);//自动装箱
    6. coll.add(new Date());
    7. System.out.println(coll);
    8. }

    获取添加的元素的个数——int size()

    System.out.println(coll.size());//3

    将集合中的元素添加到当前的集合中——boolean addll(Collection c)

    1. Collection coll1 = new ArrayList();
    2. coll1.add("bbb");
    3. coll.addAll(coll1);
    4. System.out.println(coll);//[aaa, 123, Fri Jun 10 15:30:17 CST 2022, bbb]

    清空集合中所有的元素——void clear()

    1. coll.clear();
    2. System.out.println(coll);//[]

    判断当前集合是否为空——boolean isEmpty()

    System.out.println(coll.isEmpty());//true

    判断集合中是否包含某元素——boolean contains(Object o)   

    1. Collection coll = new ArrayList();
    2. coll.add(123);
    3. coll.add(new String("嘻戏i"));
    4. coll.add(new Person("嘻戏i",31));
    5. System.out.println(coll.contains(123));//true
    6. System.out.println(coll.contains(new String("嘻戏i")));//true
    7. //我们在判断时会调用obj对象所在类的equals()。Person类未重写equals方法则该处为false,反之为true
    8. System.out.println(coll.contains(new Person("嘻戏i",31)));//false -->true

    判断某一集合中的所有元素是否都存在于当前集合中——boolean containsAll(Collection c)

    1. Collection coll1 = Arrays.asList(123,"嘻戏i");
    2. System.out.println(coll.containsAll(coll1));//true

    从集合中移除某一元素——boolean remove(Object o)

    1. coll.remove(123);
    2. System.out.println(coll);//[嘻戏i, Person{name='嘻戏i', age=31}]

    从集合中移除某一集合中所有的元素(差集)——boolean removeAll(Collection c)

    1. coll.removeAll(coll1);
    2. System.out.println(coll);//[Person{name='嘻戏i', age=31}]去除和coll1相同的元素

    获取当前集合和另一集合的交集,并返回给当前集合boolean retainAll(Collection c)

    1. Collection coll = new ArrayList();
    2. coll.add(123);
    3. coll.add("嘻戏i");
    4. coll.add(new Person("嘻戏i",31));
    5. coll.add(false);
    6. Collection coll1 = Arrays.asList(123,"嘻戏i","aaa");
    7. coll.retainAll(coll1);
    8. System.out.println(coll);//[123, 嘻戏i]
    9. System.out.println(coll1);//[123, 嘻戏i, aaa]

    判断当前集合和形参集合是否相同——boolean equals(Object o)

    1. boolean equals = coll.equals(coll1);
    2. //要想返回true 需要当前集合和形参集合的元素都相同。(因为我们这里使用的是collection子类ArrayList是有序的,所有元素的位置也需要一致)
    3. System.out.println(equals);

    返回当前对象的哈希值——int hashcode()

    1. int i = coll.hashCode();
    2. System.out.println(i);

    集合转数组——Object[] toArray()

    1. Collection coll = new ArrayList();
    2. coll.add("嘻戏i");
    3. coll.add(123);
    4. coll.add(new Person("嘻戏i",31));
    5. Object[] objects = coll.toArray();
    6. for (int i = 0; i < objects.length; i++) {
    7. System.out.println(objects[i]);
    8. }

    数组转集合——调用Arrays类的静态方法asList()

    1. List list = Arrays.asList(new String[]{"aa","bb","cc"});
    2. System.out.println(list);//[aa, bb, cc]
    3. //基本数据类型的数组转化成集合时,会将整个数组默认一个整体
    4. List list1 = Arrays.asList(new int[]{111,222,333});
    5. System.out.println(list1);//[[I@3d82c5f3]
    6. List list2 = Arrays.asList(new Integer[]{111,222,333});
    7. System.out.println(list2);//[111, 222, 333]

    遍历集合元素:迭代器——Iterator iterator()

    1. public void test5() {
    2. Collection coll = new ArrayList();
    3. coll.add("嘻戏");
    4. coll.add(123);
    5. coll.add(new Person("嘻戏", 28));
    6. Iterator iterator = coll.iterator();//获取迭代器
    7. while (iterator.hasNext()) { //hasNext():判断是否还有下一个元素
    8. System.out.println(iterator.next()); //next():①指针下移 ②将下移以后集合位置上的元素返回
    9. }
    10. }
    •  遍历集合元素的方法:

    使用迭代器Iterator

    1. public void test5() {
    2. Collection coll = new ArrayList();
    3. coll.add("嘻戏");
    4. coll.add(123);
    5. coll.add(new Person("嘻戏", 28));
    6. Iterator iterator = coll.iterator();//获取迭代器
    7. //方式一:不推荐
    8. // for (int i = 0; i < coll.size(); i++) {
    9. // System.out.println(iterator.next());
    10. // }
    11. //方式二:推荐
    12. while (iterator.hasNext()) { //hasNext():判断是否还有下一个元素
    13. System.out.println(iterator.next()); //next():①指针下移 ②将下移以后集合位置上的元素返回
    14. }

    使用迭代器Iterator的错误方式

    下面三种错误方式代码用到的集合

    1. Collection coll = new ArrayList();
    2. coll.add("嘻戏");
    3. coll.add(123);
    4. coll.add(new Person("嘻戏", 28));
    错误方式1: 报异常:NoSuchElementException
    1. //方式1.1
    2. Iterator iterator1 = coll.iterator();
    3. while (iterator1.next() != null){
    4. System.out.println(iterator1.next());
    5. }
    6. //方式1.2
    7. System.out.println(iterator.next());
    8. System.out.println(iterator.next());
    9. //报异常:NoSuchElementException
    10. System.out.println(iterator.next());
    错误方式2 一直无限循环下去
    1. //集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。
    2. while (coll.iterator().hasNext()){
    3. System.out.println(coll.iterator().next());
    4. }
    //错误方式3 关于Iterator中的remove()
    1. //如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,再调用remove都会报IllegalStateException。
    2. Iterator iterator2 = coll.iterator();
    3. while (iterator2.hasNext()){
    4. // iterator2.remove(); //报异常:IllegalStateException
    5. //正确操作:删除集合中的new Person("嘻戏",28)
    6. Object obj = iterator2.next();
    7. if (new Person("嘻戏",28).equals(obj)){
    8. iterator2.remove();
    9. }
    10. }
    11. iterator2 = coll.iterator();
    12. while (iterator2.hasNext()){
    13. System.out.println(iterator2.next());
    14. }

    增强for循环遍历集合元素

    1. Collection coll = new ArrayList();
    2. coll.add(123);
    3. coll.add("嘻戏");
    4. coll.add(new Person("嘻戏",28));
    5. //for(集合元素的类型 局部变量 : 集合对象)
    6. //内部仍然调用了迭代器。
    7. for (Object obj: coll) {
    8. System.out.println(obj);
    9. }
    10. System.out.println("*****************");
    11. //for循环和增加for循环
    12. String[] arr = new String[]{"MM","MM","MM"};
    13. for (int i = 0; i < arr.length; i++) {
    14. // arr[i] = "GG";//改变了字符串arr
    15. }
    16. for (String s :
    17. arr) {
    18. s = "GG";//只改变了局部变量s,未改变字符串arr
    19. // System.out.println(s);
    20. }
    21. for (int i = 0; i < arr.length; i++) {
    22. System.out.println(arr[i]);
    23. }
    • List接口框架

    |----Collection接口:单列集合,用来存储一个一个的对象
              |----List接口:存储有序的、可重复的数据。  -->“动态”数组,替换原有的数组
                  |----ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储
                  |----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储
                  |----Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储

     ArrayList的源码分析

    1 jdk 7情况下
           ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementData
           list.add(123);//elementData[0] = new Integer(123);

           list.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容。
           默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中。
     
           结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)
    2 jdk 8中ArrayList的变化:
          ArrayList list = new ArrayList();//底层Object[] elementData初始化为{}.并没有创建长度为10的数组
          list.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData[0]

          后续的添加和扩容操作与jdk 7 无异。
    3 小结:jdk7中的ArrayList的对象的创建类似于单例的饿汉式,而jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。

    LinkedList的源码分析

    LinkedList list = new LinkedList(); 内部声明了Node类型的first和last属性,默认值为null
          list.add(123);//将123封装到Node中,创建了Node对象。

          其中,Node定义为:体现了LinkedList的双向链表的说法

    1. private static class Node<E> {
    2. E item;
    3. Node<E> next;
    4. Node<E> prev;
    5. Node(Node<E> prev, E element, Node<E> next) {
    6. this.item = element;
    7. this.next = next;
    8. this.prev = prev;
    9. }
    10. }

    Vector的源码分析

    jdk7和jdk8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组。在扩容方面,默认扩容为原来的数组长度的2倍。

    总结

    ArrayList、LinkedList、Vector三者的异同:

    同:三个类都是实现了List接口,存储数据的特点相同:存储有序的、可重复的数据

    异:通过上面的源代码分析

     List接口中的常用方法

    增:

    在index位置插入元素 ——void add(int index, Object ele)

    list.add(1,456);

    从index位置开始将另外集合中的所有元素添加进来 ——boolean addAll(int index, Collection eles)

    1. List list1 = Arrays.asList(1,2,3);
    2. //从list索引2的位置开始将list1中的所有元素添加进来
    3. list.addAll(2,list1);
    4. //从list末尾的位置开始将list1中的所有元素当做一个整体添加进来
    5. list.add(list1);

    删:

     移除指定索引位置的元素,并返回此元素——Object remove(int index) / boolean remove(Object obj)

    1. //删除list集合中索引为2的元素,并返回该元素
    2. Object Obj = list.remove(2);
    3. System.out.println(Obj);
    4. //删除list集合中list1集合,有就返回true,没有返回false
    5. boolean obj1 = list.remove(list1);
    6. System.out.println(obj1);

    改:

     设置指定索引位置的元素为其他元素——Object set(int index, Object ele)

    1. Object obj2 = list.set(3, 33);
    2. System.out.println(obj2);

    查:

    获取指定索引位置的元素 ——Object get(int index)

    1. Object obj3 = list.get(3);
    2. System.out.println(obj3);

    获取集合长度——int size()

    int size = list.size();

    返回obj在集合中首次出现的位置(集合中不存在查询的元素返回-1)——int indexOf(Object obj)

    int i = list.indexOf(123);

    返回obj在当前集合中末次出现的位置——int lastIndexOf(Object obj)

    int i2 = list.lastIndexOf(123);

    返回从fromIndex到toIndex位置的子集合(左闭右开)——List subList(int fromIndex, int toIndex)

    List list2 = list.subList(1, 4);

    List集合遍历

    Iterator迭代器方式

    1. Iterator iterator = list.iterator();
    2. while (iterator.hasNext()){
    3. System.out.println(iterator.next());
    4. }

    增强for循环

    1. for (Object obj : list) {
    2. System.out.println(obj);
    3. }

    普通for循环(List集合有索引,结合get方法,可以用普通for循环)

    1. for (int j = 0; j < list.size(); j++) {
    2. System.out.println(list.get(j));
    3. }

  • 相关阅读:
    Transformer学习
    Python高级程序设计(持续学习中)
    如何使用Puppeteer进行新闻网站数据抓取和聚合
    【buildroot】linux编译器版本和gcc版本version.h不一致
    快鲸物业管理系统:助力物业管理服务双提升
    5、基础算法
    Nature文章|博士后对就业更有信心 但仍是学术界的苦力
    专为小白打造—Kafka一篇文章从入门到入土
    IPD各阶段交付文档
    Java之List.steam().sorted(Comparator.comparing())排序异常解决方案
  • 原文地址:https://blog.csdn.net/m0_58052874/article/details/125220824