集合

[toc]

一、Java集合框架概述

1.1 集合框架的概述

  • 面向对象语言对事物的体现都以对象的形式,为了方便对多个对象操作,就要对对象进行存储
  • 使用 Array 存储对象方面具有 一些弊端,而 Java 集合就像一种容器,可以动态的把多个对象的引用放入容器
  • 说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt, .jpg , .avi, 数据库中)

1.1.1 数组的特点

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

1.1.2 数组的缺点

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

1.2 Java集合的两种体系

1.2.1 Collection 接口

  • 单列数据,定义了存取一组对象的方法的集合

    • List:元素有序可重复的集合。“动态“数组
      • ArrayList 、LinkedList 、Vector
    • Set:元素无序不可重复的集合。 高中讲的”集合
      • HashSet、 LinkedHashSet、TreeSet
  • Collection 接口继承树(实线是继承关系,虚线是实现关系)

    image-20201022143539482

1.2.2 Map 接口(y=f(x))

  • HasMap、LinkedHashMap、TreeMap、Hashtable、Properties

  • 双列数据,保存具有映射关系“key-value对”的集合

  • Map接口继承树(实线是继承,虚线是实现)

    image-20201022143746725

二、Collection接口方法

  • 向Collection 接口实现类的对象中添加数据obj时,要求obj所在类要重写equals().

2.1 add(Object e)

  • 元素e添加到集合中中

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

2.2 addAll(Collection coll1)

  • 集合 coll1 中的元素添加到集合中

    Collection coll = new ArrayList();
    Collection coll1 = new ArrayList();
    
    coll1.add(456);
    coll1.add("CC");
    
    coll.add(coll1);
    

2.3 size():return int;

  • 获取添加元素个数(默认值:0)

      List arr1 = Arrays.asList(new int[]{123, 456});
      System.out.println(arr1.size()); //1
    
      List arr2 = Arrays.asList(new Integer[]{123, 456});
      System.out.println(arr2.size()); //2
    

2.4 clear()

  • 清空集合的元素

    coll1.clear();
    

2.5 isEmpty()

  • 判断当前集合是否为空

    System.out.println(coll1.isEmpty());
    

2.6 contains(Object obj)

  • 判断当前集合中是否包含obj

  • 在判断的时候会调用obj对象所在类的equals()

    Collection coll = new ArrayList();
    coll.add(123);
    coll.add(456);
    coll.add(new String("Tom"));
    coll.add(false);
    coll.add(new Person("Jerry",20));
    
    
    System.out.println(coll.contains(new String("Tom"))); //true
    System.out.println(coll.contains("Tom")); //true
    System.out.println(coll.contains(new Person("Jerry",20) ));//false 
    Person p = new Person("Jerry",20);
    System.out.println(coll.contains(p)); //false
    
  • 重写equals() 后

    System.out.println(coll.contains(new Person("Jerry",20) ));//true
    Person p = new Person("Jerry",20);
    System.out.println(coll.contains(p)); //true
    

2.7 containsAll(Connection coll)

  • 判断形参coll 中所有元素是否都存在于当前集合中。

    Collection coll1 = Arrays.asList(123,456);
    System.out.println(coll.containsAll(coll1));
    

2.8 remove(Object obj)

  • 从当前集合中移除obj元素

    System.out.println(coll.remove(123));//true
    System.out.println(coll.remove(new Person("Jerry",20))); //false
    
  • 重写equals方法后

    System.out.println(coll.remove(new Person("Jerry",20))); //true
    

2.9 removeAll(Collection coll)

  • 从当前集合中移除coll中所有的元素差集: 移除两个集合共有

    Collection coll1 = Arrays.asList(123,4567);
    coll.removeAll(coll1);
    

2.10 retainAll(Collection coll1)

  • 交集:获取当前集合和coll1集合的交集,并返回给当前集合

    Collection coll1 = Arrays.asList(123,4567);
    coll.retainAll(coll1);
    System.out.println(coll); //[123]
    

2.11 equals(Object obj)

  • 要想返回true,需要当前集合和形参集合元素都相同

  • 另外就是看右边的对象有序,还是**

  • 如下是ArrayList

    Collection coll = new ArrayList();
    coll.add(123);
    coll.add(456);
    coll.add(new String("Tom"));
    coll.add(false);
    coll.add(new Person("Jerry",20));
    
    Collection coll1 = new ArrayList();
    coll1.add(456);
    coll1.add(123);
    coll1.add(false);
    coll1.add(new String("Tom"));
    coll1.add(new Person("Jerry",20));
    
    System.out.println(coll.equals(coll1)); //false
    

2.12 hasCode()

  • 返回当前对象的哈希值

    System.out.println(coll.hashCode());
    

2.13 toArray

  • 集合--> 数组

    Object[] arr = coll.toArray();
    for (Object o : arr) {
        System.out.println(o);
    
    }
    
  • 数组--->集合

    • 调用Arrays类的静态方法asList()
    List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});
    

2.14 iterator()

  • 返回Iterator 接口的实例,用于遍历集合元素

三、Iterator 迭代器接口

3.1迭代器

  • Iterator对象称为迭代器,主要用于遍历 Collection集合中的元素。
  • 集合对象每次调用iterator() 都得到一个全新的迭代器对象
  • Iterator 不是容器

3.2 迭代器模式(GOF定义)

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

3.3 next()

  • 指针下移

  • 将下移以后的集合位置上的元素返回

    Iterator iterator = coll.iterator();
    System.out.println(iterator.next());
    

3.4 hasNext()

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

    while(iterator.hasNext()){
        System.out.println(iterator.next());
    }
    

3.4 remove()

  • 可以在遍历的时候,删除集合中的元素,此方法不同于集合直接调用remove()

  • 如果未调用next()在上一次调用 next 方法之后已经调用了 remove 方法,再调用 remove 都会报IllegalStateException

    Iterator iterator = coll.iterator();
    
    while(iterator.hasNext()){
        Object obj = iterator.next();
        if(obj.equals("Tom")){
            iterator.remove();
        }
    }
    

3.5 迭代器的执行原理

image-20201022171526252

3.6 迭代器遍历的两种错误方式

//错误方式一:
Iterator iterator1 = coll.iterator();
while((iterator1.next())!=null){
    System.out.println(iterator1.next());
}

//错误方式二:每次调用iterator() 都得到一个全新的迭代器对象。默认游标都在集合的第一个元素之上
while(coll.iterator().hasNext()){
    System.out.println(coll.iterator().next());
}

3.7 使用foreach 循环遍历集合元素

  • JDK 5.0 提供了 foreach 循环迭代访问 Collection数组。

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

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

  • foreach 可以用来遍历数组

  • 内部仍然调用了迭代器

  • for(集合元素类型 局部变量 : 集合对象){}

    for (Object o : coll) {
        System.out.println(o);
    }
    
  • 遍历数组 for(数组元素的类型 局部变量 : 数组对象)

    int[] arr = new int[]{1,2,3,4,5};
    for (int i : arr) {
        System.out.println(i);
    }
    

四、Collection 子接口一:List

4.1List接口概述

  • 鉴于Java中数组用来存储数据局限性,所以通常使用List替换数组
  • List集合类中 元素有序、且可重复,集合中每个元素都有其对应的顺序索引
  • List容器中的元素都对应一个整数型的序号,可以根据序号存取容器的元素
  • JDK API 中 List接口的实现类 常用的有:ArrayList 、LinkedList 和 Vector

4.2 ArrayList、LinkedList、Vector 三者的异同

相同:

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

不同:

  • ArrayList 作为 List 接口的主要实现类线程不安全的,执行效率高底层使用Object[]存储
  • Vector 作为 List 接口的古老实现类线程安全的,效率低底层使用Object[]存储
  • LinkedList 对于频繁的插入和删除操作,使用此类效率比ArrayList高底层使用双向链表

4.3 ArrayList 的源码分析

4.3.1 JDK 7 情况下

ArrayList list = new ArrayList();   
  • 底层默认创建了长度是10 的 Object[] 数组elementData
    • list.add(123);//elementData[0] = new Integer(123);
    • ……
    • list.add(1) ; 如果此次的添加导致底层 elementData 数组容量不够,则扩容。
    • 默认情况下,扩容为原来容量的1.5倍,同时需要将原有数组中的数据复制新的数组中。
  • 结论:建议开发中使用带参的构造器: ArrayList list = new ArrayList(int capacity);

4.3.2 JDK 8 中的变化

ArrayList list = new ArrayList();   
  • 底层Object[] elementData 初始化为{} ,并没有创建长度为10的数组
  • list.add(123); //第一次调用add() 时底层才创建了长度10的数组,并将数据123 添加到elementData[0];
  • 后续的添加扩容与jdk 7.0 无异。

4.3.3 小结

  • JDK 7 中的 ArrayList 的对象的创建类似于单例 的 饿汉式
  • JDK 8 中的ArrayList 的对象的创建类似于单例 的 懒汉式延迟了数组的创建,节省了内存

4.4 LinkedList 的底层实现源码

  • prev 变量记录前一个元素的位置
  • next 变量记录下一个元素的位置
  • 体现了 LinkedList 的双向链表的说法
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.4.1源码分析

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

4.5 Vector

  • 线程安全
  • 通过 Vector() 构造器创建对象时,底层都创建了长度为10 的数组
  • 在扩容方面,默认扩容为原来的数组长度的2倍

4.6 List 接口的常用方法

4.6.1 void add(int index,Object ele)

  • 在 index 位置插入 ele 元素

    List list = new ArrayList();
    list.add(123);
    list.add(456);
    list.add(new String("Tom"));
    list.add(false);
    list.add(new Person("Jerry",20));
    
    System.out.println(list); //[123, 456, Tom, false, Person{name='Jerry', age=20}]
    
    //void add
    list.add(1,"BB"); //[123, BB, 456, Tom, false, Person{name='Jerry', age=20}]
    System.out.println(list);
    

4.6.2 boolean addAll(int index,Collection eles)

  • 从 index 位置开始将 eles 中的所有元素添加进来

    List list1 = Arrays.asList(1,2,3);
    list.addAll(list1);
    
    System.out.println(list.size()); //9
    

4.6.3 Object get(int index)

  • 获取指定 index 位置的元素

    System.out.println(list.get(0)); //123
    

4.6.4 int indexOf(Object obj)

  • 返回obj在集合中首次出现的位置

  • 不存在返回-1

    int index = list.indexOf(456);
    System.out.println(index); //1
    

4.6.5 int lastIndexOf(Object obj)

  • 返回obj在当前集合中末次出现的位置

    System.out.println(list.lastIndexOf(false)); //3
    

4.6.6 Object remove(int index)

  • 移除指定 index 位置的元素,并返回此元素

    Object obj = list.remove(0);
    System.out.println(obj); //123
    System.out.println(list); //[456, Tom, false, Person{name='Jerry', age=20}]
    

4.6.7 Object set(int index,Object ele)

  • 设置指定 index 位置的元素为 ele

    list.set(1,"CC");
    System.out.println(list); //[456, CC, false, Person{name='Jerry', age=20}]
    

4.6.8 List subList(int fromIndex,int toIndex)

  • 返回从fromIndex 到 toIndex 位置的子集合

    List list1 = list.subList(2, 4);
    System.out.println(list1); //[false, Person{name='Jerry', age=20}]
    

4.6.9 常用方法总结

方法
add(Object obj)
remove(int index) /remove(Object obj)
set(int index,Object ele)
get(int index)
add(int index,Object ele)
长度 size()
遍历 ① Iterator 迭代器遍历
② 增强for 循环
③普通 的循环

4.6.10 List 的三种遍历方式

① Iterator 迭代器遍历

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

② 增强for 循环

for (Object o : list) {
    System.out.println(o);

}

③ 普通的循环

//方式三: for
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

五、Collection 子接口二:Set

5.1 Set 接口的概述

  • 存储无序的、不可重复的数据
  • Set 接口中没有额外定义新的方法,使用的都是Collection 中声明过的方法

5.1.1 HashSet

  • 作为 Set 接口主要实现类
  • 线程不安全的,可以存储 null 值
  • 底层:数组+链表的结构
  • 对应的类一定要重写 equals() 和 hashCode(Object obj) 方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”

5.1.2 LinkedHashSet

  • 作为 HashSet 的子类,遍历其内部数据时,可以按照添加的顺序遍历

5.1.3 TreeSet

  • 可以按照添加对象的指定属性进行排序

5.2 Set 的特性分析

5.2.1无序性

  • 不等于随机性

    Set set = new HashSet();
    set.add(123);
    set.add("AA");
    set.add(new String("CC"));
    set.add(new Person("Tom",21));
    
    Iterator iterator = set.iterator();
    while(iterator.hasNext()){
        /*
        AA
        CC
        123
        Person{name='Tom', age=21}
         */
        System.out.println(iterator.next());
    }
    
  • 存储的数据在底层数组中并非按照数组索引的顺序添加,而是由数据的哈希值决定的

5.2.2 不可重复性

  • 保证添加的元素按照 equals() 判断时,不能返回 true,即:相同的元素只能添加一个

    Set set = new HashSet();
    set.add(123);
    set.add(123);
    set.add("AA");
    set.add(new String("CC"));
    set.add(new String("CC"));
    set.add(new Person("Tom",21));
    set.add(new Person("Tom",21));
    
    Iterator iterator = set.iterator();
    while(iterator.hasNext())
        /* 
        AA
        CC
        Person{name='Tom', age=21}
        123
        Person{name='Tom', age=21}
         */
        System.out.println(iterator.next());
    }
    

5.3 添加元素的过程:(HashSet 为例)

  • 向 HashSet 中添加元素 a ,首先调用元素a所在类的 hashCode() 方法,计算 a 的哈希值,此哈希值通过某种算法计算出在 HashSet 底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:

    • 情况一:如果此位置没有其他元素 则元素 a 添加成功。

    • 如果此位置有其他元素 b (或以链表形式存在的多个元素),则比较元素 a 与 元素 b 的 hash 值:

      • 情况二:如果 hash 值不相同,则元素 a 添加成功
      • 如果 hash 值相同,进而需要调用元素 a 所在类的 equals() 方法:
        • equals() 返回 true,元素 a 添加失败
        • 情况三equals() 返回 false,则元素 a 添加成功。
  • 对于添加成功的情况二和情况三而言:元素 a已经存在指定索引位置上数据链表的方式存储。

    • JDK 7:元素 a 放在数组中,指向原来的元素
    • JDK 8:原来的数组在数组总,指向元素 a
    • 总结:七上八下
    image-20201023103627894

5.4 关于 hashCode 和 equals 的重写

  • 向Set 中添加的数据,其所在的类一定要重写 hashCode() 和 equals()
  • 对应的类一定要重写 equals() 和 hashCode(Object obj) 方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”
  • 重写两个方法的小技巧:对象中用作 equals() 方法比较的 Field, 都应该用来计算 hashCode 值

5.5 LinkedHashSet

5.5.1 底层结构

image-20201023120623897

5.5.2LinkedHashSet 的使用

  • 作为 HashSet 的子类,在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据。
  • 优点:对于频繁的遍历操作,LinkedHashSet 效率高于 HashSet

5.6 TreeSet

5.6.1 要求

  • 向TreeSet 中添加的数据,要求是相同类的对象
  • 两种排序方式:自然排序(实现Compare接口)定制排序
  • 自然排序中,比较两个对象是否相同的标准为:compareTo() 返回0,不在是equals()

5.6.2底层原理(红黑树)

image-20201023140930109

5.6.3 自然排序

  • 自然排序中,比较两个对象是否相同的标准为:compareTo() 返回0,不在是equals()

    public class Person implements Comparable{
        private String name;
        private int age;
        
        /**
         * 按照姓名从大到小排列,年龄从小到大排列
         * @param o
         * @return
         */
        @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("输入的类型不匹配");
            }
        }
        
    }
    

5.6.4 定制排序

  • 定制排序中,比较两个对象是否相同的标准为:compare() 返回0,不在是equals()

    Comparator com = new Comparator(){
        /**
         * 按照年龄从小到大排序
         * @param o1
         * @param o2
         * @return
         */
        @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("输入的数据类型不匹配");
            }
        }
    };
    

六、Map接口

  • 双列数据,存储 key-value 对的数据

6.1 Map接口继承树

image-20201023163639690

6.2 Map的实现类的特点

1. HashMap:

  • 作为Map 的主要实现类:线程不安全的,效率高
  • 存储null的key 和 value
  • 底层数组+链表jdk 7 及之前
    • 数组 + 链表 + 红黑树jdk 8

1.1 LinkedHashMap:

  • 保证在遍历 Map 元素时,可以按照添加的顺序实现遍历
  • 在原有的 HashMap 底层结构基础上,添加了一对指针,指向前一个和后一个元素
  • 对于频繁的遍历操作,此类执行效率高于 HashMap

2. TreeMap:

  • 保证按照添加的 key-value 对进行排序,实现排序遍历。
  • 此时考虑 key自然排序定制排序
  • 底层使用的红黑树

3. Hashtable:

  • 作为古老的实现类:线程安全的,效率低
  • 不能存储 null 的 key 和 value

3.1 Properities:

  • 常用来处理配置文件
  • key 和 value 都是 String 类型

6.3 Map 结构的理解

  • Map 中的 key无序的、不可重复的,使用 Set 存储所有的key ---> key 所在的类要重写 equals() 和 hashCode() (以 HashMap 为例)
  • Map 中的 value无序的、可重复的,使用 Collection 存储所有的 value --> value 所在的类要重写 equals()
  • 一个键值对key-value 构成了一个 Entry 对象
  • Map 中的 entry无序的、不可重复的,使用 Set 存储所有的 entry

6.4 HashMap 的底层实现原理

6.4.1 JDK 7

HashMap map = new HashMap();
  • 实例化以后,底层创建了长度是16一维数组 Entry[] table.

    ……可能已经执行过多次put……
    map.put(key1,value1);
    
  • 首先,调用 key1 所在类的 hashCode() 计算 key1 哈希值,此哈希值经过某种算法计算后,得到 Entry数组中的存放位置

  • 如果此位置上的数据为,此时key1-value1 添加成功。 --<font color=red>情况1</font>

  • 如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据[以链表形式存在]),比较 key1 和已经存在的一个或多个数据的哈希值

    • 如果 key1 的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。--<font color=red>情况2</font>
    • 如果 key1 的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)方法:
      • 如果 equals() 返回false:此时 key1-value1 添加成功。 --<font color=red>情况3</font>
      • 如果 equals() 返回true:使用 vlaue1 替换 value2。
  • 补充:关于<font color=red>情况2</font> 和 <font color=red>情况3</font>: 此时 key1-value1原来的数据链表的方式存储。

  • 在不断添加的过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空时),默认的扩容方式扩容为原来容量的2倍,并将原有的数据复制过来。

6.4.2 JDK 8

  • new HashMap(): 底层没有创建一个长度为16的数组
  • 底层的数组是: Node[] , 而非Entry[]
  • 首次调用put() 方法时,底层创建长度为 16 的数组
  • 底层结构: 数组 + 链表 + 红黑树
    • 当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8当前数组的长度 > 64时,
    • 此时此索引位置上的所有数据改为使用红黑树存储

6.4.3 源码中的重要常量

常量
DEFAULT_INITAL_CAPACITY HashMap 的默认容量,16
MAXIMUM_CAPACITY HashMap 的最大支持容量,2^30
DEFAULT_LOAD_FACTOR HashMap 的默认加载因子,0.75
TREEIFY_THRESHOLD Bucket 中链表的长度大于该默认值,转化为红黑树 8
UNTREEIFY_THRESHOLD Bucket 中红黑树存储的Node小于该默认值,转化为链表
MIN_TREEIFY_CAPACITY 桶中的Node被树化最小的hash表容量。64
table 存储元素的数组,总是 2 的 n 次幂
entrySet 存储具体元素的集
size HashMap 中存储的键值对的数量
modCount HashMap 扩容和结构改变的次数
threshold 扩容的临界值, = 容量*填充因子 16 * 0.75 = 12
loadFactor 填充因子

6.5 LinkedHashMap 底层实现原理

  • 源码中:

  • static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after; //能够记录添加的元素的先后顺序
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }
    

6.6 Map 中定义的方法

6.6.1 Object put(Object key,Object value)

  • 将指定 key-value 添加到(或修改)当前 map 对象

    Map map = new HashMap();
    map.put("AA", 123);
    map.put("AA", 87);
    map.put("BB", 56);
    map.put(45, 123);
    

6.6.2 void putAll(Map m)

  • 将m中的所有 key-value 对存放到当前map中

    Map map1 = new HashMap();
    map1.put("CC", 123);
    map1.put("DD", 123);
    //{AA=87, BB=56, CC=123, DD=123, 45=123}
    map.putAll(map1);
    

6.6.3 Object remove(Object key)

  • 移除指定key-value对,返回value

    Object value = map.remove("CC");
    System.out.println(map); //{AA=87, BB=56, DD=123, 45=123}
    System.out.println(value); //123
    

6.6.4 void clear()

  • 清空当前 map 中的所有数据

    map.clear(); //与map = null不同
    System.out.println(map.size()); //0
    System.out.println(map);//{}
    

6.6.5 Object get(Object key)

  • 获取指定 key 对应的value

    Map  map = new HashMap();
    map.put("AA", 123);
    map.put(45, 123);
    map.put("BB", 56);
    
    System.out.println(map.get(45));//123
    

6.6.6 boolean containsKey(Object key)

  • 是否包含指定的key

    boolean isExist = map.containsKey("BB");
    System.out.println(isExist);//true
    

6.6.7 boolean containsValue(Object value)

  • 是否包含指定的value

    boolean b = map.containsValue(123);
    System.out.println(b);//true
    

6.6.8 int size()

  • 返回 map 中 key-value 对的个数

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

6.6.9 boolean isEmpty()

  • 判断当前 map 是否为空

    map.clear();
    System.out.println(map.isEmpty());//true
    

6.6.10 boolean equals(Object obj)

  • 判断当前 map 和参数对象 obj 是否相等

  • map 和 map1 中key-value都相同才为true

    Map  map1 = new HashMap();
    map1.put("AA", 123);
    map1.put(45, 123);
    map1.put("BB", 56);
    //map 和 map1 中key-value都相同才为true
    System.out.println(map.equals(map1));
    

6.6.11 Set keySet()

  • 返回所有 key 构成的 Set 集合

    Map  map = new HashMap();
    map.put("AA", 123);
    map.put(45, 123);
    map.put("BB", 56);
    
    Set set = map.keySet();
    Iterator iterator = set.iterator();
    while(iterator.hasNext()){
        System.out.println(iterator.next());
    }
    

6.6.12 Collection values()

  • 返回所有 value 构成的 Collection 集合

    Collection values = map.values();
    for (Object value : values) {
        System.out.println(value);
    
    }
    

6.6.13 Set entrySet

  • 返回所有 key-value 对构成的 Set 集合

    Set set1 = map.entrySet();
    Iterator iterator1 = set1.iterator();
    while(iterator1.hasNext()){
        Object obj = iterator1.next();
        Map.Entry entry = (Map.Entry) obj;
    
        System.out.println(entry.getKey() + " " + entry.getValue());
    }
    
  • key-value 的遍历方式二:

    Set keySet = map.keySet();
    Iterator iterator2 = keySet.iterator();
    while(iterator2.hasNext()){
        Object key = iterator2.next();
        Object value = map.get(key);
        System.out.println(key + "=" + value );
    }
    

6.7 TreeMap 的两种添加方式的使用

  • 向 TreeMap 中添加 key-value ,要求 key 必须是由同一类创建的对象

  • 因为要按照 key 进行排序自然排序 、 定制排序

6.7.1 自然排序

  • User类 实现 Comparable 接口

    TreeMap map = new TreeMap();
    User u1 = new User("Tom", 23);
    User u2 = new User("Jerry", 32);
    User u3 = new User("Jack", 20);
    User u4 = new User("Rose", 18);
    
    map.put(u1, 98);
    map.put(u2, 89);
    map.put(u3, 76);
    map.put(u4, 100);
    
    Set set = map.entrySet();
    Iterator iterator = set.iterator();
    while(iterator.hasNext()){
        Map.Entry entry =(Map.Entry) (iterator.next());
        System.out.println(entry.getKey() + "==" + entry.getValue());
    }
    

6.7.2 定义排序

  • 在创建 new TreeMap () 的时候重写Comparator 方法

    TreeMap map = new TreeMap(new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            if(o1 instanceof User && o2 instanceof User){
                User u1 = (User)o1;
                User u2 = (User)o2;
                return Integer.compare(u1.getAge(), u2.getAge());
            }
            throw new  RuntimeException("输入的类型不匹配");
        }
    });
    User u1 = new User("Tom", 23);
    User u2 = new User("Jerry", 32);
    User u3 = new User("Jack", 20);
    User u4 = new User("Rose", 18);
    
    map.put(u1, 98);
    map.put(u2, 89);
    map.put(u3, 76);
    map.put(u4, 100);
    
    Set set = map.entrySet();
    Iterator iterator = set.iterator();
    while(iterator.hasNext()){
        Map.Entry entry =(Map.Entry) (iterator.next());
        System.out.println(entry.getKey() + "==" + entry.getValue());
    }
    

6.8 Properties

  • Properties中内容

    name=Tom路飞
    password=123456
    
  • 读取Properties 的代码

          FileInputStream fis = null;
            try {
                Properties pros = new Properties();
    
                 fis = new FileInputStream("jdbc.properties");
                pros.load(fis); //加载对应的流文件
    
                String name = pros.getProperty("name");
                String password = pros.getProperty("password");
                System.out.println(name + " " +password);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if(fis != null){
                        fis.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
  • 如果读取中文出现乱码,修改如下配置:

image-20201024104940408

七、Collections工具类

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

7.1 面试题:Collection 和 Collections 的区别?

  • Collections 是操作 Collection 和 map 的工具
  • Collection 是单列数据的接口,其中常见的接口List 和 Set

7.2 排序操作(均为静态)

7.2.1 reverse(List)

  • 反转 List 中元素的顺序

    Collections.reverse(list);
    

7.2.2 shuffle(List)

  • 对 List 集合元素进行随机排序

    Collections.shuffle(list);
    

7.2.3 sort(List)

  • 根据元素的自然顺序对指定 List 结合元素按升序排序

    Collections.sort(list);
    

7.2.4 sort(List,Comparator)

  • 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序

7.2.5 swap(List,int,int)

  • 将指定的 list 结合中 i 元素 和 j 处元素进行交换

    Collections.swap(list, 1, 2);
    

7.3 查找、替换

7.3.1 Object max(Collection)

  • 根据元素的自然顺序,返回给定集合中的最大元素

7.3.2 Object max(Collection,Comparator)

  • 根据Comparator 指定的顺序,返回给定集合中的最大元素

7.3.3 Object min(Collection)

  • 根据元素的自然顺序,返回给定集合中的最小元素

7.3.4 Object min(Collection,Comparator)

  • 根据Comparator 指定的顺序,返回给定集合中的最小元素

7.3.5 int frequency(Collection, Object)

  • 返回指定集合中指定元素的出现次数

    int frequency = Collections.frequency(list, 65);
    System.out.println(frequency);
    

7.3.6 void copy(List dest,List src)

  • 将 src 中内容复制到 dest 中

  • 错误的添加方法(会报异常)

    //java.lang.IndexOutOfBoundsException: Source does not fit in dest
    //        List dest = new ArrayList();
    //        Collections.copy(dest,list);
    
  • 正确的添加方法

    List dest = Arrays.asList(new Object[list.size()]);
    Collections.copy(dest, list);
    System.out.println(dest);
    
  • 使用新值替换 List 对象的所有旧值

7.4 同步控制

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

    List list1 = Collections.synchronizedList(list); //返回线程安全的list
    
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容