【Java SE】10. Java集合

10.1 Java集合框架概述

  1. 为了方便对多个对象的操作,就要对多个对象进行存储,而Java 集合就像一种容器,可以动态地把多个对象的引用放入容器中

  2. 集合、数组都是对多个数据进行存储操作的数据结构,简称Java容器。

  3. 但使用Array存储对象方面具有一些弊端:

    1. 数组长度一旦确定后,就不能修改了,不方便
    2. 如String[ ] arr;一但定义好后,其元素的类型也就确定了,也就只能操作指定类型了(优点)
    3. 数组提供的方法十分有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高
    4. 获取数组中实际元素的个数的需求,数组没有现成的属性和方法可以用
    5. 数组存储数据的特点:有序、可重复。对无序、不可重复的需求无法满足
  4. 集合框架

    1. Collection接口:单列接口,用来存储一个一个的对象

      1. List接口:存储有序的、可重复的数据 → \to 动态数组

        • ArrayList、LinkedList、Vector
      2. Set接口:存储无序的、不可重复的数据 → \to 数学中的集合

        • HashSet、LinkedHashSet、TreeSet

        在这里插入图片描述

    2. Map接口:双列集合,用来存储一对(key-value)数据

      • HashMap、LinkedHashMap、TreeMap、Hashtable、Properties

        在这里插入图片描述

10.2 Collection接口方法

  1. add(Object obj)

    Collection coll = new ArrayList();
    
    coll.add("AA");
    coll.add("BB");
    coll.add(123);//自动装箱
    coll.add(new Date());
    
  2. size()

    System.out.println(coll.size());//4
    
  3. addAll(Collection coll)

    Collection coll1 = new ArrayList();
    coll1.add("CC");
    coll1.add(456);
    coll.addAll(coll1);
    
    System.out.println(coll.size());//6
    System.out.println(coll);
    //[AA, BB, 123, Sat Jun 05 10:02:11 CST 2021, CC, 456]
    
  4. isEmpy()、clear()

    System.out.println(coll.isEmpty());//false
    
    coll.clear();
    System.out.println(coll.isEmpty());//true
    
  5. contains(Object obj):判断当前集合中是否包含obj,判断时会调用obj对象所在类的equals方法,故向collection接口实现类的对象中添加数据obj时,要求obj所在类要重写equals()

    Collection col1 = new ArrayList();
    col1.add("123");
    col1.add(345);
    col1.add(new String("Tom"));
    col1.add(false);
    
    col1.add(new Person("Tom", 23));
    
    boolean contains = col1.contains(345);
    System.out.println(contains);//true
    System.out.println(col1.contains(123));//false
    System.out.println(col1.contains(new String("123")));//true
    
    System.out.println(col1.contains(new Person("Tom", 23)));//false
    //底层使用equals()比较,String重写了equals()比较的时内容;Person没有重写,比较的是地址
    

    若在Person类中重写equals():

    @Override
    public boolean equals(Object o) {
        System.out.println("Person equals()...");
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }
    

    则:

    System.out.println(col1.contains(new Person("Tom", 23)));
    //Tom在第五个
    //故要执行5次重写的equals()
    //true
    
  6. contains(Collection col):拿两个集合的元素挨个比较

    Collection col2 = Arrays.asList("123",345);
    System.out.println(col1.containsAll(col2));//true
    
  7. remove(Object obj):判断是否是要删除的那个元素。 只会删除找到的第一个元素

    col1.remove(345);
    System.out.println(col1);
    //[123, Tom, false, Person{name='Tom', age=23}]
    //注意:也会执行重写的equals()
    
  8. removeAll(Collection col):取当前集合的差集

    col1.removeAll(col2);
    System.out.println(col1);
    //[Tom, false, Person{name='Tom', age=23}]
    
  9. retainAll(Collection col):把交集的结果存在当前集合中

    col1.retainAll(col2);System.out.println(col1);
    //[123, 345] 可见col1被修改了
    //会将交集结果返回给调用方法的集合
    
  10. equals(Object obj):集合是否相等,注意如果时List则要看元素顺序、如果是Set那就不看元素顺序

  11. Object[] toArray():转成对象数组,集合 → \to 数组

    Object[] objects = col1.toArray();
    for (int i = 0; i < col1.size(); i++) {    
    	System.out.println(objects[i]);
    }
    //123
    //345
    //Tom
    //false
    //Person{name='Tom', age=23
    

    拓展:数组 → \to 集合,Arrays的静态方法:asList()

    Collection col2 = Arrays.asList("123",345);
    
  12. hashCode():获取集合对象的哈希值

    System.out.println(col1.hashCode());//1510696
    
  13. iterator():返回Iterator接口实例,用于遍历集合元素

10.3 Iterator迭代器接口

  1. Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素

  2. 迭代器模式:

    提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。 迭代器模式,就是为容器而生

  3. 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前

  4. Iterator接口的方法:

    1. hasNext()next()

      1. Iterator iterator = col1.iterator();
        //hasNext():判断是否还有下一个元素
        while (iterator.hasNext()){        
        //next():    
        //1.只要调用就会使指针下移     
        //2.将下移以后集合位置上的元素返回    
        	System.out.println(iterator.next());
        }
        
      2. 在调用it.next()方法之前必须要调用it.hasNext()进行检测。若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常

    2. remove()

      1. Iterator iterator = col1.iterator();
        while (iterator.hasNext()){    
        	Object next = iterator.next();    
        	if (next.equals("Tom")){        
        		iterator.remove();    
        	}
        }
        Iterator iterator1 = col1.iterator();
        while (iterator1.hasNext()){    
        	System.out.println(iterator1.next());
        }
        
      2. 注意:

        1. Iterator可以删除集合的元素, 但是是遍历过程中通过迭代器对象的remove方
          , 不是集合对象的remove方法
        2. 如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法,
          再调用remove都会报IllegalStateException
  5. foreach 循环遍历集合或数组的元素

    1. Java 5.0 提供了 foreach for (:) { }循环迭代访问 Collection和数组

    2. 遍历操作不需获取Collection或数组的长度,无需使用索引访问元素

    3. 遍历集合的底层调用Iterator完成操作

    4. foreach还可以用来遍历数组

    5. //for(集合元素的类型 局部变量 : 集合对象)
      for (Object obj:col1) {    
      	System.out.println(obj);
      }
      
    6. foreach并不会修改原集合中的内容

      for (Object obj : col1) {    
      	obj = new Person("Jack",20);
      	//只是赋值给了对象obj    
      	System.out.println(obj);
      }
      for (Object obj:col1) {    
      	System.out.println(obj);
      	//原来的集合并未发生改变
      }
      

10.4 Collection子接口一:List

  1. List接口:存储有序的、可重复的数据 → \to 动态数组

    三个实现类:

    1. ArrayList:List的主要实现类;线程不安全的,效率高(如果需要是线程安全的,则使collections工具类中的 synchronized(List<T> list) 来实现线程安全);底层使用Object[ ]数组存储(数组的动态分配)只要用到数组都可以使用ArrayList
    2. LinkedList:对于频繁的插入和删除操作,使用此类效率更高;底层使用双向链表存储
    3. Vector:List的古老实现类;线程安全的,效率低;底层使用Object[ ]数组存储(基本不用)
  2. ArrayList源码分析:

    1. ArrayList是对象引用的一个"变长"数组

    2. ArrayList的JDK1.8之前与之后的实现区别?

      1. JDK1.7: ArrayList像饿汉式,直接创建一个初始容量为10的数组,如果此次添加导致底层elementData数组不够用,则扩容,默认情况下扩容为原来的1.5倍,同时将原数组的内容复制到新数组中
      2. JDK1.8: ArrayList像懒汉式,一开始创建一个长度为0的数组 { },当添加第一个元
        素时再创建一个始容量为10的数组,扩容时,与1.7中相同

      在这里插入图片描述

  3. LinkedList源码分析:

    1. 对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高

    2. 内部声明了Node类型的first和last属性(头尾指针),默认值为null

    3. 底层使用双向链表存储,故Node的定义为:

      private static class Node<E> {
      		E item;
      		Node<E> next;
      		Node<E> prev;
      		
          Node(Node<E> prev, E element, Node<E> next) {
      				this.item = element;
      				this.next = next;
      				this.prev = prev;
      		}
      }
      

    在这里插入图片描述

  4. 面试题:请问ArrayList/LinkedList/Vector的异同? 谈谈你的理解? ArrayList底层是什么?扩容机制? Vector和ArrayList的最大区别?

    1. ArrayList和LinkedList的异同
      二者都线程不安全,相对线程安全的Vector,执行效率高。
      此外, ArrayList是实现了基于动态数组的数据结构, LinkedList基于链表的数据结构。对于
      随机访问get和set, ArrayList觉得优于LinkedList,因为LinkedList要移动指针。对于新增
      和删除操作add(特指插入)和remove, LinkedList比较占优势,因为ArrayList要移动数据
    2. ArrayList和Vector的区别
      Vector和ArrayList几乎是完全相同的,唯一的区别在于Vector是同步类(synchronized),属于
      强同步类。因此开销就比ArrayList要大,访问要慢。正常情况下,大多数的Java程序员使用
      ArrayList而不是Vector,因为同步完全可以由程序员自己来控制。 Vector每次扩容请求其大
      小的2倍空间,而ArrayList是1.5倍。 Vector还有一个子类Stack
  5. List接口方法

    1. 增:add(Object obj)

    2. 长度:size()

    3. 遍历:

      1. Iterator迭代器

        Iterator iterator = linkedList.iterator();
        while(iterator.hasNext()){    
        	System.out.println(iterator.next());
        }
        
      2. foreach循环

        for (Object obj:linkedList     ) {    
        	System.out.println(obj);
        }
        
    4. 插:void add(int index, Object ele):在index位置插入ele元素

      LinkedList linkedList  = new LinkedList();
      linkedList.add(0,21);
      ArrayList arrayList = new ArrayList();
      arrayList.add(0,12);
      //arrayList.add(2,12);IndexOutOfBoundsException,与初始化有关
      
    5. boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来

    6. 查:Object get(int index):获取指定index位置的元素

    7. 改:Object set(int index, Object ele):设置指定index位置的元素为ele

    8. int indexOf(Object obj):返回obj在集合中首次出现的位置

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

    10. 删:Object remove(int index):移除指定index位置的元素,并返回此元素

      //ArrayList在删除后都会补齐
      ArrayList arrayList = new ArrayList();
      arrayList.add(0,12);
      arrayList.add(1,21);
      arrayList.remove(0);
      System.out.println(arrayList.get(0));
      //21
      

      注:区分子接口list中的remove(int index)与collection接口中的remove(Object obj)

      LinkedList linkedList  = new LinkedList();linkedList.add(0,1);
      linkedList.add(1,2);
      linkedList.remove(1);
      System.out.println(linkedList);
      //[1]按index删除
      linkedList.remove(new Integer(1));
      System.out.println(linkedList);
      //[]按value删除
      
    11. List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的左闭右开子集合,原list不会改变,只会返回想要的子元素

    12. boolean contains(Object obj):判断元素是否在动态数组中

10.5 Collection子接口二:Set

  1. Set接口:存储无序的、不可重复的数据 → \to 数学中的集合

    1. HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
      • LinkedHashSet:作为HashSet的子类:使得遍历其内部数据时,可以按照添加顺序遍历
    2. TreeSet:可以按照添加对象的指定属性,进行排序
  2. Set的无序性:HashSet为例说明

    1. 不等于随机性
    2. 存储的数据在底层数组中,并非按照数组索引的顺序添加,而是根据数据的哈希值添加的
  3. Set的不可重复性:

    1. 保证添加的元素按照equals( )判断时,不能返回true
    2. 相同的元素只能添加一次
  4. Set中添加元素的过程:(以HashSet为例说明)

    1. 首先调用元素a所在类的hashCode( )方法,计算出元素a的哈希值

    2. 通过某种算法计算出在HashSet底层数组中存放的位置(索引位置)

    3. 判断数组此位置上

      1. 没有元素:则元素a添加成功
      2. 有其他元素b(或以链表形式存在的多个元素):比较元素a与b的哈希值
        1. 如果哈希值不相同:则元素a添加成功
        2. 如果哈希值相同:调用元素a所在类的equals( ),返回true,元素a添加失败;返回false,元素添加成功
    4. 说明:对于添加成功的情况2和情况3而言:元素a与已经存在指定位置上的数据以链表的形式存储

      在这里插入图片描述

  5. 向Set中添加的数据,元素所在的类一定要重写equals( )和hashCode( ),且重写的方法必须具有一致性:相等的对象必须具有相等的散列码

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Person)) return false;
    
        Person person = (Person) o;
    
        if (age != person.age) return false;
        return name != null ? name.equals(person.name) : person.name == null;
    }
    
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
    

    以Eclipse/IDEA为例,在自定义类中可以调用工具自动重写equals和hashCode。
    问题: 为什么用Eclipse/IDEA复写hashCode方法,有31这个数字?

    1. 选择系数的时候要选择尽量大的系数。因为如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。(减少冲突)
    2. 并且31只占用5bits,相乘造成数据溢出的概率较小
    3. 31可以 由i*31== (i<<5)-1来表示,现在很多虚拟机里面都有做相关优化。 (提高算法效率)
    4. 31是一个素数,素数作用就是如果我用一个数字来乘以这个素数,那么最终出来的结果只能被素数本身和被乘数还有1来整除! (减少冲突)
  6. LinkedHashSet:

    1. LinkedHashSet 是 HashSet 的子类

    2. LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的

    3. LinkedHashSet插入性能略低于 HashSet, 但在频繁遍历全部元素时有很好的性能

      在这里插入图片描述

  7. TreeSet:

    1. 向TreeSet 添加数据,要求数据是相同类的对象

    2. TreeSet 是 SortedSet 接口的实现类, TreeSet 可以确保集合元素处于排序状态

    3. 两种排序方式:

      1. 自然排序:

        1. 元素类实现Comparable接口,并重写元素类中的compareTo(Object o)

          //按name排序,name相同的按照age排
          @Override
          public int compareTo(Object o) {
              if(o instanceof Person){
                  Person person = (Person) o;
                  int compare = -this.name.compareTo(person.name);
                  if(compare != 0){
                      return compare;
                  }else {
                      return Integer.compare(this.age,person.age);
                  }
              }else {
                  throw new RuntimeException("输入的数据类型不匹配");
              }
          }
          
          TreeSet set = new TreeSet();
          set.add(new Person("Tom",22));
          set.add(new Person("Jack",20));
          set.add(new Person("Jack",18));
          
          for (Object obj:set
               ) {
              System.out.println(obj);
          }
          //Person{name='Tom', age=22}
          //Person{name='Jack', age=18}
          //Person{name='Jack', age=20}
          
        2. 自然排序中,比较两个对象是否相同的标准为:compareTo( )返回0不再是equals( )

      2. 定制排序:

        1. new一个comparator排序器

          Comparator comparator = new Comparator() {
              @Override
              public int compare(Object o1, Object o2) {
                  if(o1 instanceof Person && o2 instanceof Person){
                      Person p1 = (Person) o1;
                      Person p2 = (Person) o2;
                      return Integer.compare(p1.getAge(),p2.getAge());
                  }else {
                      throw new RuntimeException("输入的数据类型不匹配");
                  }
              }
          };
          
          TreeSet set = new TreeSet(comparator);
          set.add(new Person("Tom",22));
          set.add(new Person("Jack",20));
          set.add(new Person("Jack",18));
          
          for (Object obj:set
               ) {
              System.out.println(obj);
          }
          
        2. 定制排序中,比较两个对象是否相同的标准为:compare( )返回0不再是equals( )

10.6 Map接口

  1. Map:双列数据,存储key-value对的数据

    1. HashMap:作为Map的主要实现类;线程不安全的,效率高;键值都可以为null
      1. LinkHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历,原因时在原有的HashMap结构上,添加了一对指针指向前后的元素
    2. TreeMap:保证按照添加的key-value对进行排序,实现排序遍历,此时考虑key的自然排序,底层使用红黑树
    3. Hashtable:古老的实现类;线程安全的,效率不高,键值都不可以为null
      1. Properties:常用来处理配置文件,key和value都是String类型
  2. Map结构的理解

    1. Map中的key:无序的、不可重复的,使用Set存储所有的key

      • key所在的类要重写equals( )和hashCode( )
    2. Map中的value:无序的、可重复的,使用Collection存储所有的value

      • value所在的类要重写equals( )
    3. 一个键值对:key-value构成了一个Entry对象

    4. Map中的Entry:无序的、不可重复的,也使用Set存储所有的entry

      在这里插入图片描述

  3. ⭐HashMap的底层实现原理:(以jdk7为例)

    1. 创建HashMap对象,实例化以后,底层创建了长度是16的一维数组Entry [ ] table

      HashMap hashMap = new HashMap();
      
    2. 首先调用key1所在类的hashCode( )计算key1的哈希值,此哈希值经过某种算法计算后,得到Entry数组中存放的位置

      ⭐属性 → h a s h C o d e ( ) \to^{hashCode()} hashCode() → \to 哈希值 → 某 种 算 法 \to^{某种算法} → \to 哈希表的索引位置 → 若 位 置 相 同 , 比 较 哈 希 值 \to^{若位置相同,比较哈希值} → 若 哈 希 值 相 同 , 用 e q u a l s ( ) 比 较 k e y \to^{若哈希值相同,用equals()比较key} equals()key → 若 k e y 相 同 , 替 换 v a l u e \to^{若key相同,替换value} keyvalue

      hashMap.put(key1,value1);
      
      1. 如果此位置上数据为空,此时key1-value1添加成功,放到数组中
      2. 如果此位置上存在一个或多个数据(以链表形式存在),比较key1和已经存在的数据的哈希值
        1. 不同:key1-value1添加成功,链进去
        2. 和某一个数据(key2-value2)的哈希值相同:继续比较,调用key1所在类的equals( )方法比较key是否相同
          1. 返回false:此时key1-value1添加成功,链进去
          2. 返回true:使用value1替换相同key的value2值(保证key不能重复)
    3. 在不断添加的过程中,涉及到扩容问题,默认的扩容方式:扩容为原来的2倍,并将原有的数据复制过来

    4. JDK 8相较于JDK 7的不同:

      1. new HashMap( ):底层并没有创建一个长度为16的数组

        public HashMap() {
                this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
        }
        
      2. jdk 8 底层的数组是:Node[ ],而非Entry[ ]

        static class Node<K,V> implements Map.Entry<K,V> {}
        
      3. 首次调用put( )时,底层才创建一个长度为16的数组

      4. jdk 7底层结构:只有数组+链表;jdk 8底层结构:数组+链表+红黑树

        • 在这里插入图片描述

        • 在这里插入图片描述

        • 当数组某一个索引位置上的元素以链表形式存在的数据个数>8,且当前数组长度> 64时,此时索引位置上所有数据改为使用红黑树存储

    面试题:

    1. 谈谈你对HashMap中put/get方法的认识?如果了解再谈谈HashMap的扩容机制?默认大小是多少?什么是负载因子(或填充比)? 什么是吞吐临界值(或阈值、 threshold)?

    2. 负载因子值的大小,对HashMap有什么影响

      答:

      1. 负载因子的大小决定了HashMap的数据密度
      2. 负载因子越大密度越大,发生碰撞的几率越高,数组中的链表越容易长,造成查询或插入时的比较次数增多,性能会下降
      3. 负载因子越小,就越容易触发扩容,数据密度也越小,意味着发生碰撞的几率越小,数组中的链表也就越短,查询和插入时比较的次数也越小,性能会更高。但是会浪费一定的内容空间。而且经常扩容也会影响性能,建议初始化预设大一点的空间
      4. 按照其他语言的参考及研究经验,会考虑将负载因子设置为0.7~0.75,此时平均检索长度接近于常数
  4. Map接口中定义的方法

    1. 添加、 删除、修改操作:

      1. Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
      2. void putAll(Map m):将m中的所有key-value对存放到当前map中
      3. Object remove(Object key):移除指定key的key-value对,并返回value
      4. void clear():清空当前map中的所有数据
    2. 元素查询的操作:

      1. Object get(Object key):获取指定key对应的value
      2. boolean containsKey(Object key):是否包含指定的key
      3. boolean containsValue(Object value):是否包含指定的value
      4. int size():返回map中key-value对的个数
      5. boolean isEmpty():判断当前map是否为空
      6. boolean equals(Object obj):判断当前map和参数对象obj是否相等
    3. 元视图操作的方法(得到集合后,可以使用集合的遍历方式进行遍历):

      1. Set keySet():返回所有key构成的Set集合

        HashMap hashMap = new HashMap();
        hashMap.put(1,2);
        hashMap.put("Tom",22);
        hashMap.put("Tom","abc");//这里的put是修改
        
        Set set = hashMap.keySet();
        
        for (Object obj:set
             ) {
            System.out.println(obj);
        }
        //1
        //Tom
        
      2. Collection values():返回所有value构成的Collection集合

        Collection values = hashMap.values();
        
        Iterator iterator = values.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //2
        //abc
        
      3. Set entrySet():返回所有key-value对构成的Set集合

        Set set1 = hashMap.entrySet();
        
        for (Object obj:set1
        ) {
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
        //1:2
        //Tom:abc
        
  5. TreeMap:

    1. TreeMap存储 Key-Value 对时, 需要根据 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态

    2. TreeSet底层使用红黑树结构存储数据

    3. TreeMap 的 Key 的排序

      1. 自然排序: TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
      2. 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现Comparable 接口
    4. TreeMap判断两个key相等的标准:

      两个key通过compareTo()方法或者compare()方法返回0

  6. Properties:

    1. Properties 类是 Hashtable 的子类,该对象用于处理属性文件

    2. 由于属性文件里的 key、 value 都是字符串类型,所以 Properties 里的 key和 value 都是字符串类型

    3. 存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法

      public static void main(String[] args) {
          FileInputStream fileInputStream = null;
          try {
              Properties properties = new Properties();
              fileInputStream = new FileInputStream("jdbc.properties");
              properties.load(fileInputStream);
      
              String name = properties.getProperty("name");
              String password = properties.getProperty("password");
              System.out.println(name+"-"+password);
          		//TOM-123
              
          } catch (IOException e) {
              e.printStackTrace();
          }finally {
              if(fileInputStream != null){
                  try {
                      fileInputStream.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      

10.7 Collections工具类

  1. Collections 是一个操作 Set、 List 和 Map 等集合的工具类

  2. 提供了一系列静态的方法对集合元素进行排序、查询和修改等操作:

    1. 排序操作:(均为static方法)

      1. reverse(List): 反转 List 中元素的顺序
      2. shuffle(List): 对 List 集合元素进行随机排序
      3. sort(List): 根据元素的自然顺序对指定 List 集合元素按升序排序
      4. sort(List, Comparator): 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
      5. swap(List, int, int): 将指定 list 集合中的 i 处元素和 j 处元素进行交换
    2. 查找、替换

      1. Object max(Collection): 根据元素的自然顺序,返回给定集合中的最大元素

      2. Object max(Collection, Comparator): 根据 Comparator 指定的顺序,返回给定集合中的最大元素

      3. Object min(Collection)

      4. Object min(Collection, Comparator)

      5. int frequency(Collection, Object): 返回指定集合中指定元素的出现次数

      6. void copy(List dest,List src):将src中的内容复制到dest中

        //复制时要保证dest和src的size相同
        List list = new ArrayList();
        list.add(1);
        list.add(2);
        
        //错误的:
        //List list1 = new ArrayList();
        //IndexOutOfBoundsException
        
        List list1 = Arrays.asList(new Object[list.size()]);
        Collections.copy(list1,list);
        System.out.println(list1);//[1, 2]
        
      7. boolean replaceAll(List list, Object oldVal, Object newVal): 使用新值替换List 对象的所有旧值

    3. 同步控制:

      1. Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题

      2. ArrayList和HashMap都不是线程安全的:

        List list = new ArrayList();
        list.add(1);
        list.add(2);
        
        //返回的list1即为线程安全的
        List list1 = Collections.synchronizedList(list);
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值