面试题-容器类,并发包

java 容器都有哪些

 

Collection 和 Collections 有什么区别?

答: Collection 是集合接口,提供了对集合对象最基本的通用接口方法. 定义了集合最大化统一操作方式. Collections 是一个工具类, 包含了各种集合操作的静态方法(对集合的搜索、排序、线程安全化等), 这个类不能实例化, 只是一个工具类, 类似Arrays.

 

List、Set、Map 之间的区别是什么?

 List中的元素,有序、可重复、可为空;

    Set中的元素,无序、不重复、只有一个空元素;

    Map中的元素,无序、键不重,值可重、可一个空键、多可空值;

 

hashmap的数据结构?

答:数组+链表
数组里面放的是链表的第一个值
链表放的是hash后产生冲突的值

 

hashmap.put(a,b)做了那几个操作?

答:首先计算a的hashing值,然后根据a的hashing值找到a所对象的桶(busket),取出当前桶里面所存放的链表,遍历链表,看是否存在key为a的对象,如果有,就将原来的值返回,并覆盖上新值b。最后将entry加入到链顶。

 

为什么hashmap是无序的?

答:因为hashmap的默认容量是16,负载因子是0.75。就是当hashmap填充了75%的busket是就会扩容,最小的可能性是(16*0.75),一般为原内存的2倍,然后rehash,这时候导致了hashmap的无序性。
 

 

HashMap 和 Hashtable 有什么区别?

HashMap是HashTable的轻量级实现(非线程安全的实现),它们都实现了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,效率上高于HashTable。

HashMap允许将null作为一个entry的key或者value,而HashTable不允许。

HashMap去掉了HashTable的contains方法,改成containsValue和containsKey方法。

二者最大的不同是,HashTable的方法是synchronized(线程安全的),而HashMap不是,在多个线程访问HashTable时,不需要自己为它的方法实现同步,而HashMap就必须为之提供外同步。

初始容量大小和每次扩充容量大小的不同 : ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。

底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制

 

  ConcurrentHashMap,这个需要细看

       ConcurrentHashMap从JDK1.5开始随java.util.concurrent包一起引入JDK中,主要为了解决HashMap线程不安全和Hashtable效率不高的问题。

     而JDK1.7之前的ConcurrentHashMap使用分段锁机制实现,JDK1.8则使用数组+链表+红黑树数据结构和CAS原子操作实现ConcurrentHashMap;

 

如何决定使用 HashMap 还是 TreeMap?

答: TreeMap的Key值是要求实现java.lang.Comparable,所以迭代的时候TreeMap默认是按照Key值升序排序的;TreeMap的实现也是基于红黑树结构。而HashMap的Key值实现散列hashCode(),分布是散列的均匀的,不支持排序;数据结构主要是桶(数组),链表或红黑树。大多情况下HashMap有更好的性能,所以大多不需要排序的时候我们会使用HashMap.

 

说一下 HashMap 的实现原理,需要细看

答: 基于1.8. HashMap的内部实现为一个数组, 每个元素称为桶bucket, 每个元素为Node, 包含key, value, Node类型的next, 还有个hash值. HashMap的初始容量是16, 默认填充因子是0.75, 当容量不够时其扩容按N*2扩容. 当桶中元素不大于8时数据结构是个列表, 当大于是转化为红黑树, 当红黑树元素小于6时退化为列表.

hash的方法和定位, 先对hash值计算, 方法是高16位与低16位异或运算, 然后用容量n-1与hash结果与运算, 算出下标.

resize 的处理, 因为容量都是2的N次幂, 所以调整size的时候可以原位不变, 在高位填充随机的0或1. 即移动一个2次幂的位置. resize可以均匀的把冲突的节点分布到新的桶中了.

 

说一下 HashSet 的实现原理,需要细看

答: HashSet 基于 HashMap实现. 但仅仅使用key来实现各种特性. 内部定义了一个假值用来操作.

 

ArrayList 和 LinkedList 的区别是什么?

      1. ArrayList的实现是基于数组,LinkedList的实现是基于双向链表。 
      2. 对于随机访问,ArrayList优于LinkedList,ArrayList可以根据下标以O(1)时间复杂度对元素进行随机访问。而LinkedList的每一个元素都依靠地址指针和它后一个元素连接在一起,在这种情况下,查找某个元素的时间复杂度是O(n) 

      3. 对于插入和删除操作,LinkedList优于ArrayList,因为当元素被添加到LinkedList任意位置的时候,不需要像ArrayList那样重新计算大小或者是更新索引。 

  4. LinkedList比ArrayList更占内存,因为LinkedList的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。

 

记一道有关list.remove的题

List list=....
for(Object obj:list){
  list.remove(obj);
}
大多数会ConcurrentModifyException
解决方式:可以切换成CopyOnWriteArrayList,这两种方式的remove是不一样的
还可以用迭代和倒删的方式

如何实现数组和 List 之间的转换?

答: List#toArray()方法将List转为数组, new ArrayList(Arrays.asList()) 方法将数组转为List.

 

ArrayList ,LinkedList和 Vector 的区别是什么?

  1. ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
  2. Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
  3. LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
  4. vector是线程(Thread)同步(Synchronized)的,所以它也是线程安全的,而Arraylist是线程异步(ASynchronized)的,是不安全的。如果不考虑到线程的安全因素,一般用Arraylist效率比较高。
  5. 如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%.公式为:新容量 = 旧容量*1.5 + 1,如过在集合中使用数据量比较大的数据,用vector有一定的优势。

  6. 如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,都是0(1),这个时候使用vector和arraylist都可以。而
    如果移动一个指定位置的数据花费的时间为0(n-i)n为总长度,这个时候就应该考虑到使用Linkedlist,因为它移动一个指定位置的数据
    所花费的时间为0(1),而查询一个指定位置的数据时花费的时间为0(i)。
    ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,
    都允许直接序号索引元素,但是插入数据要设计到数组元素移动 等内存操作,所以索引数据快插入数据慢,
    Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差
    ,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!

  7. 笼统来说:LinkedList:增删改快
                  ArrayList:查询快(有索引的存在)

Array 和 ArrayList 有何区别?

 1.存储内容比较: Array 数组可以包含基本类型和对象类型, ArrayList 却只能包含对象类型。 Array 数组在存放的时候一定是同种类型的元素。ArrayList 就不一定了 。

2、空间大小比较: Array 数组的空间大小是固定的,所以需要事前确定合适的空间大小。 ArrayList 的空间是动态增长的,而且,每次添加新的元素的时候都会检查内部数组的空间是否足够。

3.方法上的比较: ArrayList 方法上比 Array 更多样化,比如添加全部 addAll()、删除全部 removeAll()、返回迭代器 iterator() 等。

 

ArrayList、LinkedList、Vector、HashSet、Treeset、HashMap、TreeMap的区别和适用场景

  转:https://www.iteye.com/blog/bs-yg-2253605

 

在 Queue 中 poll()和 remove()有什么区别?

Queue 中 remove() 和 poll()都是用来从队列头部删除一个元素。

在队列元素为空的情况下,remove() 方法会抛出NoSuchElementException异常,poll() 方法只会返回 null

 

哪些集合类是线程安全的?

答: HashTable, Vector,Stack, concurrent包下面的集合类, ConcurrentHashMap,ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentLinkedQueue、ConcurrentLinkedDeque等, CopyOnWriteArrayList, CopyOnWriteArraySet.

 

迭代器 Iterator 是什么?

答: Iterator是个接口, 实现了该接口的类一般是集合类, 能够遍历集合中的元素. 迭代器是一种设计模式. Java中的Iterator只能单向移动, 包含的方法next(),hasNext(),remove(). 迭代器取代了原来的Enumeration接口.

 

Iterator 怎么使用?有什么特点?

答: while(iterator.hasNext()){...} Iterator的特点是更加安全, 因为它可以确保在遍历的集合元素被修改后抛出ConcurrentModiicationException

 

Iterator 和 ListIterator 有什么区别?

答: ListIterator 扩展了 Iterator. 当然Iterator有的功能ListIterator就有. 但ListIterator新增了一些额外的功能, 比如添加,替换获取前面或后面元素的索引位置. 另外, ListIterator是双向的.

 

怎么确保一个集合不能被修改?

答: 可以使用Collections类的静态方法unmodifiableCollection()方法创建只读集合. 任何改变集合的操作都将抛出java.lang.UnsupportedOperationException

 

jdk1.5后的并发包

https://blog.csdn.net/weixin_43844810/article/details/89703136

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值