集合的特点:1、对象封装数据,对象多了也需要存储,集合用于存储对象。2、对象的个数确定用数组,不确定则用集合。
集合与数组的区别
1、数组定长,集合不定长;
2、数组可以存基本数据类型,也可以存储引用类型,集合只能存储引用类型数据;
3、数组的数据必须是同一种类型,集合中的数据可以是不同的数据类型。
说说 List,Set,Map 三者的区别?三者底层的数据结构?
答:首先,Java中有Map和Collection两大容器,Collection有set、List、Queue作为子接口,所以Java中常用的三大接口。
List是指有序的可重复集合,典型的实现有ArrayList和LinckedList;其中ArrayList基于动态数组实现,LinckedList基于双向链表。查找元素效率高,但增加删除效率低(因为可能会引起元素位置改变,要维护顺序)。
Set是一个不允许有重复元素的无序集合,hashSet,TreeSet是典型的实现;hashset是基于hashmap实现的,TreeSet是基于红黑树实现。查找元素效率低,但增加删除元素效率高。
Map是键值对集合,其中键是唯一的,常见的实现有hashmap和treemap;hashmap基于散列实现,而treemap基于红黑树。
比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同
实现数据结构:hashmap、双向链表、红黑树
顺序:没有明确顺序,适合快速查找、按插入顺序、按树的比较顺序
性能:O(1)、近似于O(1)、O(logn)
空间:消耗最小、要维护双向链表的顺序,消耗较大、树结构消耗更大
有哪些集合是线程不安全的?怎么解决呢?
答:安全的有vector、stack、hashtable和枚举类型。
不安全的有:ArrayList LinkedList HashMap HashSet TreeSet TreeMap、ConcurrentHashMap等 这些集合在多线程环境中进行修改时可能会导致意外行为。
可以通过以下几种策略解决:
使用线程安全版本的集合如vector和stack等;使用Collections.synchronizedXXX() 方法转换成线程安全的集合;使用读写锁;写时复制。
HashMap 和 Hashtable 的区别?HashMap 和 HashSet 区别?HashMap 和 TreeMap 区别?
同步性
性能:线程安全性能肯定低一些;Map和Tree分别是O(1)、O(logn)
实现方式
顺序
null键和null值:hashmap允许一个null键和多个null值,hashset中允许有一个nll值,hashtable不允许。
为什么hashmap线程不安全而hashtable线程安全?
答:主要是因为它的所有公共方法都被synchronized关键字修饰了,意味着在多线程环境中,同时间内只会有一个实例对象能访问hashtable的实例,hashmap不是性能安全的,因为他没有任何同步它的方法。
ArrayList 和 LinkedList 的区别是什么?
实现方式、同步性、删除修改的性能、空间消耗。
hashSet的实现原理是什么?如何检查重复,如何保证数据不可重复?
答:hashset基于hashmap实现,因为hashmap的键是唯一的,所以hashset的值存放在键中,这样就保证了hashset中的元素不重复。hashset在存放数据的时候需要对hashcode和equals都进行比较,如果在hashcode中找到了重复的元素就比较equals,两者都一样就认定这个元素重复不存储,否则重新散列存储。
hashMap的底层原理是什么?
答:基于哈希表的map接口实现的,它允许null作为键和值。选用数组和链表的数据结构来实现。当尝试存储一个键值对时(put方法),首先要计算键的hashcode,一般是对数组的长度取模来实现,以决定存储的位置,如果该位置为空,放入新元素;如果两个以上的键hashcode映射到同一个位置时,认为发生了哈希冲突,采用链表来解决,即使用链表插入到重复元素的后面。
每次put的时候都会进行扩容检查,即查看当前hashmap的大小是否超过了其阈值(数组大小*负载因子,默认为0.75),如果超过了,就将数组翻倍,并重新分配数据。
hashmap是线程不安全的,在多线程情况下修改数据可能会发生意外。
HashMap是如何实现扩容的?它的长度为什么是 2 的幂次方?
答:如果hashmap的大小超过了阈值(数组长度*负载因子)就需要扩容,首先确定新的数组大小,并新建数组,一般是原数组的2倍,旧数组里的数据都要重新进行哈希,如果新位置为空,直接放置,如果重复,用链表插入在后面。
数组长度是2 的幂次方:
1、优化索引计算,使用2的幂次方时,能够使用哈希值和其容量-1快速得出索引位置,这比取模运算更快。避免选择质数作为容量,提升索引性能。
2、方便扩容,新的容量简单地是原来的2倍,使得数据迁移相对简单。
是为了实现高效快速的索引,同时也为了方便实现扩容。