聊一聊Java中容器体系结构
Collection:集合接口
List:是Collection的子接口,用来存储有序的数据集合
ArrayList:是List集合的实现类,底层采用动态数组进行存储数据,默认是空数组,如果存值则扩容至10,如果不够则以1.5倍进行扩容。
LinkedList:是List集合的实现类,底层采用双向链表结构进行存储数据,增删数据比较方便,速度快。
Vector :Vector类实现了可扩展的对象数组, 像数组一样,它包含可以使用整数索引访问的组件。但是,Vector的大小可以根据需要增长或缩小,以适应在创建Vector之后添加和删除。
Set: 是Collection的子接口,用来存储无序的数据集合
HashSet:底层采用哈希表(HashMap)的方式存储数据,数据无序且唯一
TreeSet:采用有序二叉树进行存储数据,遵循了自然排序。
Map: 与Collection并列,用来存储具有映射关系(key-value)的数据
HashMap:哈希表结构存储数据,key值可以为null
TreeMap:红黑树算法的实现
HashTable:哈希表实现,key值不可以为null
Properties:HashTable的子类,键值对存储数据均为String类型,主要用来操作以.properties结尾的配置文件。
【特点】存储数据是以key,value对进行存储,其中key值是以Set集合形式存储,唯一且不可重复。value是以Collection形式存储,可以重复。
List、Set和Map的区别,以及各自的优缺点
List : 可以允许重复的对象。可以插入多个null元素。是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
Set : 不允许重复对象。无序容器,无法保证每个元素的存储顺序,
Map : Map不是collection的子接口或者实现类。Map是一个接口。
Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。
TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序。
Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。
ArrayList,LinkedList,Vector的区别
ArrayList和Vector是基于数组实现的。查询快, 修改快, 添加和删除慢
ArrayList线程不安全,速度快,
Vector线程安全,速度慢,
LinkedList是基于双向链表实现的, 线程不安全, 添加, 删除快, 查询和修改慢.
ArrayList添加时进行扩容,第一次添加扩充到10,之后扩容时原来长度的1.5倍
Vector初始化的时候,默认长度为10
Vector默认情况下扩容后的容量是之前的2倍
Vector可以设置容量增量,而ArrayList不可以
TreeSet如何保证对象的有序性
TreeSet底层依赖于TreeMap,TreeMap的数据结构是二叉树(红黑树),由底层数据结构决定了TreeSet中元素有序且唯一。
我们使用TreeSet时,如果添加对象的话,我们就必须去实现Comparable或Comparator接口,来保证对象的有序性。
HashTable、HashMap、TreeMap的区别
Hashtable、HashMap、TreeMap都实现了Map接口,使用键值对的形式存储数据和操作数据。
Hashtable线程安全,key和value都不能是null值。
HashMap线程不安全,支持key和value为null的情况。
TreeMap是基于红黑树的一种提供顺序访问的Map
说一下 HashSet 的实现原理
HashSet 底层由HashMap实现,而HashMap底层使用了哈希表来支持的,特点:存储快,
HashMap的底层数据存储结构
哈希表实现的,JDK8之前分为数组+链表,之后数组+链表+红黑树
1.默认创建一个长度16,加载因子0.75的数组,数组名table
2.HashMap添加根据哈希值跟数组的长度计算出应存入的位置(数组长度-1&哈希值),而遍历是从头开始遍历,所以存取顺序不一样
3.在添加时,HashMap先判断当前位置是否为null,如果为null则存入,
否者调用equals方法比较属性值,,一样则不存,
不一样存入数组形成链表(JDK8之前新元素存入链表,老元素挂在下面,之后新元素直接挂在下面)
4.加载因子0.75(扩容时机),16*0.75=12,当数组元素达到12个时,数组扩容成原数组长度的两倍
5.当链表长度大于等于8而且数组长度大于等于64时,数组自动转换为红黑树数据结构
6.HashMap是利用hashcode和equals方法来保证去重的
7.HashMap是由多个数据结构组成其中链表和红黑树是不具备索引的所以取消了
什么是Hash碰撞以及常见的解决方案
Hash碰撞 : 对象Hash的前提是实现equals()和hashCode()两个方法,那么HashCode()的作用就是保证对象返回唯一hash值,但当两个不同对象计算值一样时,这就发生了碰撞冲突。
解决方案:
开放地址法(再散列法)开放地执法有一个公式:Hi=(H(key)+di) MOD m i=1,2,…,k(k<=m-1)
其中,m为哈希表的表长。di 是产生冲突的时候的增量序列。如果di值可能为1,2,3,…m-1,称线性探测再散列。
如果di取1,则每次冲突之后,向后移动1个位置.如果di取值可能为1,-1,2,-2,4,-4,9,-9,16,-16,…kk,-kk(k<=m/2),称二次探测再散列。如果di取值可能为伪随机数列。称伪随机探测再散列。
再哈希法Rehash当发生冲突时,使用第二个、第三个、哈希函数计算地址,直到无冲突时。
缺点:计算时间增加。
比如上面第一次按照姓首字母进行哈希,如果产生冲突可以按照姓字母首字母第二位进行哈希,再冲突,第三位,直到不冲突为止.这种方法不易产生聚集,但增加了计算时间。
链地址法(拉链法)将所有关键字为同义词的记录存储在同一线性链表中.基本思想:将所有哈希地址为i的元素构成一个称为同义词
链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。
HashMap在多线程操作中会出现什么问题!
会出现线程安全问题(比如说key值重复), 可以使用加锁解决, 但是速度慢, 所以建议使用juc包下的ConcurrentHashMap替代HashMap, 速度快且线程安全.
HashSet和TreeSet有什么区别?
HashSet是由一个hash表来实现的,因此,它的元素是无序的。add(),remove(),contains()方法的时间复杂度是O(1)。
TreeSet是由一个红黑树的结构来实现的,它里面的元素是有序的。因此,add(),remove(),contains()方法的时间复杂度是O(logn)。