Java(四):Java集合( Collection ,Map)、Collections工具类

目录

 

Java集合

Collection接口

 Iterator

List

Set接口

 Hashset

LinkedHashSet 

TreeSet

Map接口

HashMap

LinkedHashMap

Hashtable

Properties 

TreeMap

Collections工具类


Java集合

Java 集合可分为 Collection 和 Map 两大体系

数组的特点与弊端

  • 数组在内存存储方面的特点
    • 数组初始化以后,长度就确定了。
    • 数组中的添加的元素是依次紧密排列的,有序的,可以重复的。
    • 数组声明的类型,就决定了进行元素初始化时的类型。不是此类型的变量,就不能添加。
    • 可以存储基本数据类型值,也可以存储引用数据类型的变量
  • 数组在存储数据方面的弊端
    • 数组初始化以后,长度就不可变了,不便于扩展
    • 数组中提供的属性和方法少,不便于进行添加、删除、插入、获取元素个数等操作,且效率不高。
    • 数组存储数据的特点单一,只能存储有序的、可以重复的数据
  • Java 集合框架中的类可以用于存储多个对象,还可用于保存具有映射关系的关联数组。

Collection接口

  • Collection接口:用于存储一个一个的数据,也称单列数据集合

    • List子接口:用来存储有序的、可以重复的数据(主要用来替换数组,"动态"数组)
      • 实现类:ArrayList(主要实现类)、LinkedList、Vector
    • Set子接口:用来存储无序的、不可重复的数据(类似于高中讲的"集合")

      • 实现类:HashSet(主要实现类)、LinkedHashSet、TreeSet

 

(1)add(obj):添加元素对象到当前集合中

(2)addAll(Collection other):添加other集合中的所有元素对象到当前集合中

public class Main {
    public static void main(String[] args) {
        Collection coll = new ArrayList<>();
        coll.add(122);
        coll.add("!@3");
        coll.add(new person("ASd",22));
        System.out.println(coll); // [122, !@3, person@3b07d329]

        Collection coll2 = new ArrayList<>();
        coll2.add(2222);
        coll2.add("asdasd");
        coll.addAll(coll2);

        System.out.println(coll); //[122, !@3, person@3b07d329, 2222, asdasd]
    }
}

class person{
    String name;
    int age;
    public person(String name,int age){
        this.name = name;
        this.age = age;
    }
}

(3)int size():获取当前集合中实际存储的元素个数

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

(5)boolean contains(Object obj):判断当前集合中是否存在一个与obj对象equals返回true的元素

(6)boolean containsAll(Collection coll):判断coll集合中的元素是否在当前集合中都存在。即coll集合是否是当前集合的“子集”

(7)boolean equals(Object obj):判断当前集合与obj是否相等
(8)void clear():清空集合元素

(9) boolean remove(Object obj) :从当前集合中删除第一个找到的与obj对象equals返回true的元素。

(10)boolean removeAll(Collection coll):从当前集合中删除所有与coll集合中相同的元素。

(11)boolean retainAll(Collection coll):从当前集合中删除两个集合中不同的元素,使得当前集合仅保留与coll集合中的元素相同的元素,即当前集合中仅保留两个集合的交集,即this = this ∩ coll;

(12)hashCode():获取集合对象的哈希值

(13)Collection.toArray():集合转换为数组

(14)Arrays.aslist(object):数组转换为集合,这里的实参只能是对象,如果是基本数据结构,会看成一个整体

(14)iterator():返回迭代器对象,用于集合遍历 

        Collection coll = new ArrayList<>();
        coll.add(122);
        coll.add(12322);
        coll.add(122);

        Object[] num = coll.toArray();
        System.out.println(Arrays.toString(num));  //[122, 12322, 122]

        String[] arr = new String[]{"aSD","SAW","WQQ"};
        Collection list = Arrays.asList(arr);
        System.out.println(list);  //[aSD, SAW, WQQ]


        int[] num1 = new int[]{1,2,3};
        Collection list1 = Arrays.asList(num1);
        System.out.println(list1.size());  //1

        Integer[] num2 = new Integer[]{1,2,3};
        Collection list2 = Arrays.asList(num2);
        System.out.println(list2.size());  //3

 Iterator

Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,用于遍历集合中的元素

  • Iterator接口的常用方法如下:

    • public E next():返回迭代的下一个元素。
    • public boolean hasNext():如果仍有元素可以迭代,则返回 true。
    public static void main(String[] args) {
        Collection coll = new ArrayList<>();
        coll.add(122);
        coll.add(12322);
        coll.add(1223);

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

    }

Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素,接下来通过一个图例来演示Iterator对象迭代元素的过程:

使用Iterator迭代器删除元素:

java.util.Iterator迭代器中有一个方法:void remove() ;

例如遍历删除偶数

        Collection coll = new ArrayList();
        coll.add(1);
        coll.add(2);
        coll.add(3);
        coll.add(4);
        coll.add(5);
        coll.add(6);

        Iterator iterator = coll.iterator();
        while(iterator.hasNext()){

            Integer element = (Integer) iterator.next();
            if(element % 2 == 0){
                iterator.remove();
                System.out.println(coll);
            }
        }

如果直接使用collection中的remove方法,会报错,因为删除元素后,iteraror的指向会错乱

遍历还可以采用foreach方法

        Collection coll = new ArrayList();
        coll.add(1);
        coll.add(2);
        coll.add("Adasd");
        for( Object num:coll){
            System.out.println(num);
        }

List

  • 鉴于Java中数组用来存储数据的局限性,我们通常使用java.util.List替代数组

  • List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。

  • JDK API中List接口的实现类常用的有:ArrayListLinkedListVector

相关api

  • void add(int index, Object ele):在index位置插入ele元素
  • boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
  • List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
  • int indexOf(Object obj):返回obj在集合中首次出现的位置
  • int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
  • Object remove(int index):移除指定index位置的元素,并返回此元素

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

list的三个实现类: 

ArrayList:动态数组,类似于python中的list

LinkedList:双向链表,适合频繁的删除、插入元素的情况,特有方法:

  • void addFirst(Object obj)
  • void addLast(Object obj)
  • Object getFirst()
  • Object getLast()
  • Object removeFirst()
  • Object removeLast()

Vector:

  • Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList相同,区别之处在于Vector是线程安全的。
  • 在各种List中,最好把ArrayList作为默认选择。当插入、删除频繁时,使用LinkedList;Vector总是比ArrayList慢,所以尽量避免使用
  • 特有方法:
    • void addElement(Object obj)
    • void insertElementAt(Object obj,int index)
    • void setElementAt(Object obj,int index)
    • void removeElement(Object obj)
    • void removeAllElements()

ArrayList和Vector的区别

相同点:

1、ArrayList和Vector都是继承了相同的父类和实现了相同的接口

2、底层都是数组实现的

3、初始默认长度都为10。

不同点:

1、同步性:

        Vector中的public方法多数添加了synchronized关键字,以确保方法同步,也即是Vector线程安全,ArrayList线程不安全。

2、内部属性不同

        ArrayList有两个属性,存储数据的数组elementData,和存储记录数目的size。

        Vector有三个属性,存储数据的数组elementData,存储记录数目的elementCount,还有扩展数组大小的扩展因子capacityIncrement。

3、扩容不同

        ArrayList:在满足扩容条件时,扩展后数组大小为原数组长度的1.5倍与传递参数中较大者

        Vector:当扩容因子大于0时,新数组长度为原数组长度+扩容因子,否则子新数组长度为原数组长度的2倍。 将上面生成的新数组长度与传递的参数长度作比较,较大者为最终的新长度。

Set接口

  • Set接口是Collection的子接口,Set接口相较于Collection接口没有提供额外的方法
  • Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。
  • Set集合支持的遍历方式和Collection集合一样:foreach和Iterator。
  • Set的常用实现类有:HashSet、TreeSet、LinkedHashSet。

 Hashset

  • HashSet 是 Set 接口的主要实现类,大多数时候使用 Set 集合时都使用这个实现类。底层实现的是HashMap,即使用数组+单向链表+红黑树结构进行存储

  • HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存储、查找、删除性能。

  • HashSet 具有以下特点

    • 不能保证元素的排列顺序
    • HashSet 不是线程安全的
    • 集合元素可以是 null
  • HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法得到的哈希值相等,并且两个对象的 equals()方法返回值为true。

  • 对于存放在Set容器中的对象,对应的类一定要重写hashCode()和equals(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。

  • HashSet集合中元素的无序性,不等同于随机性。这里的无序性与元素的添加位置有关。具体来说:我们在添加每一个元素到数组中时,具体的存储位置是由元素的hashCode()调用后返回的hash值决定的。导致在数组中每个元素不是依次紧密存放的,表现出一定的无序性。

添加元素的过程:

  • 第1步:当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法得到该对象的 hashCode值,然后根据 hashCode值,通过某个散列函数决定该对象在 HashSet 底层数组中的存储位置。

  • 第2步:如果要在数组中存储的位置上没有元素,则直接添加成功。

  • 第3步:如果要在数组中存储的位置上有元素,则继续比较:

    • 如果两个元素的hashCode值不相等,则添加成功(通过链表的方式继续存储,具体可以查 hash冲突的解决方法)
    • 如果两个元素的hashCode()值相等,则会继续调用equals()方法:
      • 如果equals()方法结果为false,则添加成功。
      • 如果equals()方法结果为true,则添加失败。
        HashSet set = new HashSet();
        set.add("张三");
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("王五");
        set.add("赵六");

        System.out.println("set = " + set);//set = [李四, 张三, 王五, 赵六]

重写hashCode和equals:

class Person{
    String name;
    int age;

    public Person(int age,String name){
        this.name = name;
        this.age = age;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name,age);
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){return true;}
        if(obj == null || getClass() !=obj.getClass()){return false;}
        Person p = (Person) obj;
        return name == p.name && age == p.age;
    }

    @Override
    public String toString() {
        return name+"-"+age;
    }
}

思考题

        HashSet set = new HashSet();
        Person p1 = new Person(1001,"AA");
        Person p2 = new Person(1002,"BB");

        set.add(p1);
        set.add(p2);
        p1.name = "CC";
        set.remove(p1);
        System.out.println(set);//[BB-1002, CC-1001]

        set.add(new Person(1001,"CC"));//[BB-1002, CC-1001, CC-1001]
        System.out.println(set);


        set.add(new Person(1001,"AA"));
        System.out.println(set);//[BB-1002, CC-1001, CC-1001, AA-1001]

这里删除失败是因为:最开始AA的hash值假设是3,那么改为CC之后,哈希值其实是没变的,so当删除P1时,计算P1的hash值不是3(此时hash值是按照CC算的),所以就找不到之前那个AA的位置,删除失败 

LinkedHashSet 
  • LinkedHashSet 是 HashSet 的子类,不允许集合元素重复。

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

  • LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能

        //LinkedHashSet set = new LinkedHashSet();  //[AA-1001, BB-1002, dd-213]
        HashSet set = new HashSet(); //[dd-213, BB-1002, AA-1001]
        Person p1 = new Person(1001,"AA");
        Person p2 = new Person(1002,"BB");
        set.add(p1);
        set.add(p2);
        set.add(new Person(213,"dd"));
        System.out.println(set);

TreeSet

  • TreeSet 是 SortedSet 接口的实现类,TreeSet 可以按照添加的元素的指定的属性的大小顺序进行遍历。
  • TreeSet底层使用红黑树结构存储数据
  • 新增的方法如下: (了解)
    • Comparator comparator()
    • Object first()
    • Object last()
    • Object lower(Object e)
    • Object higher(Object e)
    • SortedSet subSet(fromElement, toElement)
    • SortedSet headSet(toElement)
    • SortedSet tailSet(fromElement)
  • TreeSet特点:不允许重复、实现排序(自然排序或定制排序)
  • 因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象
        TreeSet set = new TreeSet();

        set.add("MM");
        set.add("CC");
        set.add("AA");
        set.add("DD");
        set.add("ZZ");

        System.out.println(set);//[AA, CC, DD, MM, ZZ]

对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(Object obj) 或compare(Object o1,Object o2)方法比较返回值。返回值为0,则认为两个对象相等。所以TreeSet中的类必须继承Comparable接口,实现compareTo方法

所以不需要重写hashCode方法和equals方法了

  • TreeSet 两种排序方法:自然排序定制排序。默认情况下,TreeSet 采用自然排序。
    • 自然排序:TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列。
      • 如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。
      • 实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。
    • 定制排序:如果元素所属的类没有实现Comparable接口,或不希望按照升序(默认情况)的方式排列元素或希望按照其它属性大小进行排序,则考虑使用定制排序。定制排序,通过Comparator接口来实现。需要重写compare(T o1,T o2)方法。
      • 利用int compare(T o1,T o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。
      • 要实现定制排序,需要将实现Comparator接口的实例作为形参传递给TreeSet的构造器。

 自然排序:


public class Main {

    public static void main(String[] args) {
        TreeSet set = new TreeSet();

        set.add(new Person(12,"lee"));
        set.add(new Person(2,"le"));
        set.add(new Person(122,"liu"));
        set.add(new Person(22,"zhou"));
        set.add(new Person(37,"hua"));

        System.out.println(set);//[le-2, lee-12, zhou-22, hua-37, liu-122]

    }
}

class Person implements Comparable{
    String name;
    int age;

    public Person(int age,String name){
        this.name = name;
        this.age = age;
    }


    @Override
    public String toString() {
        return name+"-"+age;
    }

    @Override
    public int compareTo(Object o) {
        if(this == o){return 0;}
        if(o instanceof Person){
            Person p = (Person)o;
            return this.age - p.age;
        }
        throw new RuntimeException("类型不匹配");
    }
}

上面这种情况在compareTo方法中只比较了age的大小,也就是说当age相同时,treeSet会认为二者相同,后加进来的对象是无法add成功的

可以重写比较逻辑

    public int compareTo(Object o) {
        if(this == o){return 0;}
        if(o instanceof Person){
            Person p = (Person)o;
            int value = this.age - p.age;
            if(value!=0){
                return value;
            }else {
                return this.name.compareTo(p.name);
            }

        }
        throw new RuntimeException("类型不匹配");
    }

定制类型

        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;
                    int value = - p1.age + p2.age;
                    if(value!=0){
                        return value;
                    }else {
                        return - p1.name.compareTo(p2.name);
                    }
                }else{
                    throw new RuntimeException("lala");
                }
            }
        };

        TreeSet set = new TreeSet(comparator);

        set.add(new Person(12,"lee"));
        set.add(new Person(22,"le"));
        set.add(new Person(122,"liu"));
        set.add(new Person(22,"zhou"));
        set.add(new Person(37,"hua"));

        System.out.println(set);//[liu-122, hua-37, zhou-22, le-22, lee-12]

Map接口

  • Map 中的 key 和 value 都可以是任何引用类型的数据。但常用String类作为Map的“键”。

  • Map接口的常用实现类:HashMapLinkedHashMapTreeMap和``Properties。其中,HashMap是 Map 接口使用频率最高`的实现类

Map常用方法

  • 添加、修改操作:
    • Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中,当修改时,也可以用这个
    • void putAll(Map m):将m中的所有key-value对存放到当前map中
  • 删除操作:
    • Object remove(Object key):移除指定key的key-value对,并返回value
    • void clear():清空当前map中的所有数据
  • 元素查询的操作:
    • Object get(Object key):获取指定key对应的value
    • boolean containsKey(Object key):是否包含指定的key
    • boolean containsValue(Object value):是否包含指定的value
    • int size():返回map中key-value对的个数
    • boolean isEmpty():判断当前map是否为空
    • boolean equals(Object obj):判断当前map和参数对象obj是否相等
  • 元视图操作的方法:
    • Set keySet():返回所有key构成的Set集合
    • Collection values():返回所有value构成的Collection集合
    • Set entrySet():返回所有key-value对构成的Set集合

HashMap

  • HashMap是 Map 接口使用频率最高的实现类。
  • HashMap是线程不安全的。允许添加 null 键和 null 值。
  • 存储数据采用的哈希表结构,底层使用一维数组+单向链表+红黑树进行key-value数据的存储。与HashSet一样,元素的存取顺序不能保证一致。
  • HashMap 判断两个key相等的标准是:两个 key 的hashCode值相等,通过 equals() 方法返回 true。
  • HashMap 判断两个value相等的标准是:两个 value 通过 equals() 方法返回 true。
        HashMap map = new HashMap();
        map.put("lee",1);
        System.out.println(map);
  •  HashMap中的所有的kev彼此之间是不可重复的、无序的。所有的kev就构成一个Set集合。--->key所在的类要重写hashcode()和equals()
  • HashMap中的所有的value彼此之间是可重复的、无序的。所有的value就构成一个Collection集合。--->valve所在的类要重写equals()
  • HashMap中的-个key-valve,就构成了-个entry。
  • HashMap中的所有的entry彼此之间是不可重复的、无序的。所有的entry就构成了一个Set集合。

LinkedHashMap

  • 存储数据采用的哈希表结构+链表结构,在HashMap存储结构的基础上,使用了一对双向链表记录添加元素的先后顺序,可以保证遍历元素时,与添加的顺序一致。
  • 通过哈希表结构可以保证键的唯一、不重复,需要键所在类重写hashCode()方法、equals()方法。

Hashtable

  • Hashtable是Map接口的古老实现类,JDK1.0就提供了。不同于HashMap,Hashtable是线程安全的。
  • Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构(数组+单向链表),查询速度快。
  • 与HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序
  • Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。
  • 与HashMap不同,Hashtable 不允许使用 null 作为 key 或 value。

面试题:Hashtable和HashMap的区别

HashMap:底层是一个哈希表(jdk7:数组+链表;jdk8:数组+链表+红黑树),是一个线程不安全的集合,执行效率高
Hashtable:底层也是一个哈希表(数组+链表),是一个线程安全的集合,执行效率低

HashMap集合:可以存储null的键、null的值
Hashtable集合,不能存储null的键、null的值

Hashtable和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了。所以HashMap是Map的主要实现类,Hashtable是Map的古老实现类。

Hashtable的子类Properties(配置文件)依然活跃在历史舞台
Properties集合是一个唯一和IO流相结合的集合

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

  • 由于属性文件里的 key、value 都是字符串类型,所以 Properties 中要求 key 和 value 都是字符串类型

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

        properties.setProperty("user","songhk");
        properties.setProperty("password","123456");
        System.out.println(properties);//{password=123456, user=songhk}

 一般来说用于处理文件数据

例如创建info.property:

name=tom
password=123456

然后

        Properties pros = new Properties();
        try {
            pros.load(new FileInputStream("test/info.properties"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String user = pros.getProperty("name");
        System.out.println(user); //tom
        pros.setProperty("name","lee");
        System.out.println(pros);//{password=123456, name=lee}

TreeMap

  • TreeMap存储 key-value 对时,需要根据 key-value 的key进行排序。TreeMap 可以保证所有的 key-value 对处于有序状态
  • TreeSet底层使用红黑树结构存储数据
  • TreeMap 的 Key 的排序:
    • 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
    • 定制排序:创建 TreeMap 时,构造器传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
  • TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0。
        TreeMap map = new TreeMap();

        map.put("CC",45);
        map.put("MM",78);
        map.put("DD",56);
        map.put("GG",89);
        map.put("JJ",99);

        Set entrySet = map.entrySet();
        for(Object entry : entrySet){
            System.out.println(entry);
        }

Collections工具类

排序操作:

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

查找

  • Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
  • Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
  • Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素
  • Object min(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最小元素
  • int binarySearch(List list,T key)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。
  • int binarySearch(List list,T key,Comparator c)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定。
  • int frequency(Collection c,Object o):返回指定集合中指定元素的出现次数

复制、替换

  • void copy(List dest,List src):将src中的内容复制到dest中
  • boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
  • 提供了多个unmodifiableXxx()方法,该方法返回指定 Xxx的不可修改的视图。

添加

  • boolean addAll(Collection c,T... elements)将所有指定元素添加到指定 collection 中。

同步

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值