关于集合类

120 阅读4分钟

Collection和Collections的区别

  • Collection是个集合接口,像List,Set,Map就是他的子接口。
  • Collections是一个集合的工具类,里面包含了许多操作集合的静态方法,此类不能被实例化。

常用集合类的使用

  • ArrayList:动态数组,初始大小10,每次扩容为当前大小 * 1.5 + 1(加1是为了如果当前大小为1时也能扩容),线程不安全
  • LinkedList: 内部使用双向列表,随机增删的效率更高,非线程安全。
  • Vector: 和ArrayList类似,不一样的是他是线程安全的,因此他效率会慢些。
  • HashSet: 内部使用HashMap实现,存放进去的key无序且不会重复,如果存自定义的对象的话,要重写hashCode和头equals方法,线程不安全。
  • treeSet: 存放有序的,要存自定义对象的话同上,另外还需实现Comparable接口,线程不安全。
  • LinkedHashSet: 继承了HashSet,存储按插入的顺序排序,线程也是不安全。
  • HashMap: key-value对,key和value都允许为空,线程不安全。
  • HashTable: key-value都不允许为空,线程安全。

SynchronizedList和Vector的区别

  • SynchronizedList的同步代码块锁定的是mutex对象,Vector锁定的是this对象。那么mutex对象又是什么呢? 其实SynchronizedList有一个构造函数可以传入一个Object,如果在调用的时候显示的传入一个对象,那么锁定的就是用户传入的对象。如果没有指定,那么锁定的也是this对象
  • 如果使用add方法,那么他们的扩容机制不一样
  • SynchronizedList可以指定锁定的对象

Set如何保证元素不重复

  • 先比较对象的hashCode,不同的话直接插入
  • hashCode相同的话再比较equals(),不同的话插入
  • hashCode不同的话不执行equals()

HashMap、HashTable、ConcurrentHashMap区别

  • HashMap 线程不安全,key value值可以为null
  • HashTable 线程安全,key value值不能为null 相对HashMap性能较差
  • ConcurrentHashMap jdk1.5出的,比HashTable扩展性更好

Java 8中stream相关用法

  • 首先要的到Stream实例 可以自己构造 : Stream.of() 可以list.stream()
  • 然后用这个实例去调执行操作方法例如filter(),map()等等
  • 最后如果执行collect(Collectors.toList()) 则是将操作后的集合汇总在一个list里

Collection如何迭代

  • list.iterator() 得到的实例.hasNext()判断是否有后续值,有的话继续用实例.Next遍历
  • map.values() 得到一个Collection实例再调iterator(),后续一样

Enumeration和Iterator的区别

  • Enumeration的效率是Iterator的两倍,但是不安全
  • Iterator可以用remove()删除元素,Enumeration不可以
  • Iterator是现在主流的迭代器

如何在遍历的同时删除ArrayList中的元素

  • 用for循环从0还是遍历,匹配到要删除的下标时执行remove()执行删除,然后执行i--,不然会少遍历一个
  • 同上方法for循环,从list.size()往下递减遍历,匹配再remove()删除,就没有上面的问题
  • 用Iterator,匹配后remove()就行了

fail-fast 和 fail-safe

  • fail-fast 快速失败: 在用迭代器遍历集合的时候,如果集合的结构发生了变化,就会停止遍历,抛出异常。(结构上的变化是指集合的元素被删除或新增,修改不算)
  • fail-safe 安全失败: 在开始用迭代器遍历集合的时候,会复制一份,遍历复制出来的副本,避免上上面的问题,原集合结构上的修改不会影响到这个线程的遍历,java.util.concurrent包下的容器都是安全失败,可以在多线程下使用,并发修改。

CopyOnWriteArrayList

  • 新增方法: 执行新增方法,先加锁,再复制一个相同的新集合,新增操作在新数组上完成,再将array指向新的数组,解锁。
  • 执行修改,删除和上面的操作类似,但是执行遍历操作的是原数组。
  • 缺点: 经常曾删改的话很消耗内存。只能保证数据最终一致性,不能保证数据实时一致性。

ConcurrentSkipListMap

  • 使用场景:需要排序的东西不需要持久化或为了更高的效率,直接再内存中进行排序
  • 链表的插删性能比较好,数组在查询的性能比较好,跳跃表在这里做了折中,对于频繁的插删查操作,是个不错的选择,空间换时间。