欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java集合总结

程序员文章站 2022-05-03 08:18:11
...

原文地址: https://blog.csdn.net/IT_PL/article/details/79150046

List和Set的区别
1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 ,实现类有HashSet,TreeSet。
3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 ,实现类有ArrayList,LinkedList,Vector,CopyOnWriteArrayList。

ArrayList与Vector的区别

  1. 两者都是基于索引,内部结构是数组
  2. 元素存取有序并都允许为null
  3. 都支持fail-fast机制
  4. Vector是同步的,不会过载,而ArrayList不是,但ArrayList效率比Vector高,如果在迭代中对集合做修改可以使用CopyOnWriteArrayList
  5. 初始容量都为10,但ArrayList默认增长为原来的50%,而Vector默认增长为原来的一倍,并且可以设置
  6. ArrayList更通用,可以使用Collections工具类获取同步列表和只读列表

适用场景分析:
1、Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。
2、如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。

ArrayList与LinkedList的区别

  1. 两者都是List接口的实现类
  2. ArrayList是基于动态数组的数据结构,而LinkedList是基于链表的数据结构
  3. 对于随机访问get和set(查询操作),ArrayList要优于LinkedList,因为LinkedList要移动指针
  4. 对于增删操作(add和remove),LinkedList优于ArrayList

适用场景分析:
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList

CopyOnWriteArrayList
1. CopyOnWriteArrayList是ArrayList的线程安全的变体,其中的所有可变操作(add, set等)都是对底层数组进行一次新的复制来实现的,相比ArrayList的要慢一些,适用于读多写少的场景
2. 在并发操作容器对象时不会抛出ConcurrentModificationException,并且返回的元素与迭代器创建时的元素是一致的
3. 容器对象的复制需要一定的开销,如果对象占用内存过大,可能造成频繁的YoungGC和Full GC
4. CopyOnWriteArrayList不能保证数据实时一致性,只能保证最终一致性

CopyOnWriteArrayList添加元素源码如下:

 public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

HashMap和HashTable的区别
1. 都是基于hash表实现的,每个元素都是key-value对,内部都是通过单向链表解决冲突,容量都会自动增长
HashMap默认容量为16,每次扩容变为原来的2倍,HashTable初始容量为11,每次扩容变为原来的2倍加1
2. HashMap继承自AbstractMap类,HashTable继承自Dictionary类,
3. HashTable是同步的,适合多线程环境,而HashMap不是,但效率相对较高
4. HashMap允许key和value为null,而HashTable不允许
5. Hash值的使用不同,HashTable直接使用对象的hashcode值,而HashMap重新计算hash值
6. 在Java1.4中引入了HashMap的子类LinkedHashMap,若需要遍历顺序,可以从HashMap转向LinkedHashMap, 而HashTable的顺序是不可预知的
7. HashMap提供对key的Set进行遍历,因此它支持fail-fast机制,而HashTable提供对key的Enumeration进行遍历,不支持fail-fast
8. HashTable被认为是个遗留的类,如果在迭代的时候修改Map,可以使用ConcurrentHashMap(Java5出现)
9. HashTable产生于JDK1.1,而HashMap产生于JDK1.2

HashSet与TreeSet

  1. HashSet不能保证元素的排列顺序,TreeSet是SortedSet接口的唯一实现类,可以确保集合元素处于排序状态
  2. HashSet底层用的是哈希表,TreeSet采用的数据结构是红黑树
  3. HashSet中元素可以是null,但只能有一个,TreeSet不允许放入null

适用场景分析:
HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。

HashMap和ConcurrentHashMap的区别
1、HashMap不是线程安全的,而ConcurrentHashMap是线程安全的。
2、ConcurrentHashMap采用锁分段技术,将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个小的片段segment,而且每个小的片段segment上面都有锁存在,那么在插入元素的时候就需要先找到应该插入到哪一个片段segment,然后再在这个片段上面进行插入,而且这里还需要获取segment锁。
3、ConcurrentHashMap让锁的粒度更精细一些,并发性能更好。

Enumeration和Iterator的区别
1. Enumeration是JDK1.0出现的,只能读取集合的数据;
Iterator是JDK1.2出现的,用来替代Enumeration,增加了remove()方法,可以在迭代过程中移除元素
2. Iterator的方法名是标准化的
3. Iterator支持fail-fast机制,而Enumeration不支持
4. Enumeration的内存占用较少,效率比Iterator高,但Iterator更安全

Iterator和ListIterator的区别
1. ListIterator继承自Iterator接口,然后添加了一些额外的功能
2. 两者都有hasNext()和next()方法,可以实现顺序向后遍历,ListIterator还有hasPrevious()和previous()方法,可以实现逆序遍历
3. 都有remove()方法可以实现删除对象,ListIterator还有添加方法add()和修改方法set(),可以实现添加和修改对象,
Iterator的协议不能确保迭代的次序,所以没有提供add()方法
4. Iterator可以遍历Set和List集合,而ListIterator只能遍历List集合
5. ListIterator有nextIndex()和previousIndex()方法,可以定位当前的索引位置,Iterator没有此功能

附:集合的遍历

遍历ArrayList

import java.util.*;

public class ArrayListTest{
 public static void main(String[] args) {
     List<String> list=new ArrayList<String>();
     list.add("Hello");
     list.add("Java");
     list.add("ArrayList");
     //方法一:使用for或foreach遍历
     for (String str : list) {  
        System.out.println(str);
     }

     //方法二:将集合转化为数组,然后进行for或foreach遍历
     String[] strArray=new String[list.size()];
     list.toArray(strArray);
     for(int i=0;i<strArray.length;i++) 
     {
        System.out.println(strArray[i]);
     }

    //方法三:使用迭代器器
     Iterator<String> iterator=list.iterator();
     while(iterator.hasNext())//判断下一个元素之后有值
     {
         System.out.println(iterator.next());
     }
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

遍历Map

import java.util.*;

public class MapTest {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("1", "Hello");
        map.put("2", "Java");
        map.put("3", "Map");

        //方法一:先通过Map.keySet遍历key,再通过key获取value值
        for (String key : map.keySet()) {
            System.out.println("key= "+ key + " and value= " + map.get(key));
        }

        //方法二:通过Map.entrySet使用iterator遍历键值对对象,再通过getKey()和getValue()获取key和value的值
        Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();
            System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
        }

        //方法三:通过Map.entrySet遍历key和value
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
        }

        //方法四:通过Map.values()遍历所有的value,但不能遍历key
        for (String value : map.values()) {
            System.out.println("value= " + value);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

遍历Set

import java.util.HashSet;
import java.util.Iterator;

public class SetTest {
    public static void main(String[] args) {
        HashSet<String> sets = new HashSet<>();
        sets.add("h");
        sets.add("e");
        sets.add("l");
        sets.add("l");//不可重复
        sets.add("0");

        //方法一:迭代遍历
        for (Iterator<String> iterator = sets.iterator(); iterator.hasNext();){
            System.out.println(iterator.next());
        }
        //输出结果:
        /*
        0
        e
        h
        l
         */
       //可以看出Set集合是不可重复(添加重复操作不会报错)且无序的

        //方法二:foreach循环(没有普通for循环方法)
        for (String value:sets) {
            System.out.println(value);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

Tips:
任何对象加入集合类后,自动转变为Object类型,所以在取出的时候,需要进行强制类型转换。
任何对象没有使用泛型之前会自动转换Object类型,使用泛型之后不用强制转换。

相关标签: 集合

上一篇: H5全栈_动画

下一篇: Spring事务实践