海康威视面经
Java基础
java常用集合 及其优缺点
单列集合Collection
包含List和Set接口
List
特点:
有序:存储和取出位置一致
不唯一:包含重复元素
分类
- ArrayList:底层是数组,查询快,增删慢,线程不安全,效率高
- Vector:底层是数组,查询快,增删慢,线程安全,效率低
- LinkedList:底层是链表,查询慢,增删快,线程不安全,效率高
Set接口的基本介绍
1)无序(添加和取出的顺序不一致),取出的顺序虽然不是添加的顺序,但是它的顺序是固定的。
2)唯一:不允许有重复元素;可以存放null,最多包含一个null
3)没有索引,故不能使用索引的方法来获取元素
1.HashSet
底层是哈希表,而哈希表又依赖两个方法hashcode()和equals()
因为哈希表是无序所以这个也无序
底层具体实现逻辑:
判定哈希值是否相同
相同:通过equals方法进一步判断
返回True,则不处理
返回false,则添加至集合
不同:直接将元素添加至集合
2.TreeSet
底层是红黑树(可以保持平衡的二叉树)
特点:有序,唯一
排序的两种方式 - 自然顺序:通过让元素所属的类继承接口Comparable的compareto()方法,进行具体的大小比对操作
- 比较器排序:主要是实现Compator接口的Compare()方法,一般通过匿名内部类来操作,便于维护
遍历方式:
1.通过迭代器
2.通过增强for
双列集合Map
键值对映射:Map容器中的元素是以键值对的形式存储的,每个键对应一个值。通过键可以快速查找对应的值。
键不重复:Map中的键是唯一的,每个键对应一个值。如果添加已经存在的键,则会更新对应的值。
常用操作:Map提供了添加键值对、获取值、判断是否包含某个键等基本操作。
遍历:可以通过键集、值集或者键值对集合来遍历Map中的元素。
HashTable
线程安全:Hashtable 是同步的,可以在多线程环境中安全地使用。这意味着多个线程可以同时读写 Hashtable 而不会出现并发问题。
不允许 null 键或值:Hashtable 不允许键或值为 null,如果尝试插入 null 键或值,会抛出 NullPointerException 异常。
初始容量和加载因子:Hashtable 有一个初始容量和加载因子,当哈希表中的元素数量超过加载因子乘以容量时,哈希表会自动扩容。
HashMap
非线程安全:HashMap 不是同步的,因此不适合在多线程环境中直接使用。如果需要在多线程环境中使用,可以通过 Collections.synchronizedMap 方法来创建一个线程安全的 Map。
允许 null 键和值:在 Java 8 之后,HashMap 允许 null 作为键和值。
初始容量和负载因子:HashMap 有一个初始容量和负载因子。当哈希表中的元素数量超过负载因子乘以容量时,哈希表会自动扩容。
TreeMap
有序性:TreeMap中的键值对根据键的自然顺序或自定义排序规则进行排序,因此可以按照键的顺序进行遍历。
红黑树:TreeMap内部使用红黑树作为数据结构,这种自平衡二叉搜索树能够保持键值对的有序性,并且提供了较快的插入、删除和查找操作。
键的唯一性:TreeMap中的键是唯一的,如果尝试插入一个已存在的键,则会覆盖原有的值。
性能:TreeMap提供了对数时间复杂度的插入、删除和查找操作,适合于需要有序存储和查找的场景。
导航方法:TreeMap提供了许多导航方法,如firstKey()、lastKey()、lowerKey(K key)、higherKey(K key)等,可以方便地进行范围查找和导航操作。
ArrayList
ArrayList特点:底层是数组,查询快,增删慢,线程不安全,效率高
ArrayList如何扩容:
(1)ArrayList中维护了一个Object类型的数组elementData
transient Object[] elementData;//transient表示瞬间,短`暂的,表示该属性不会被序列化
(2)当创建ArrayList对象时,如果使用的是无参构造器。则初始elementData容量为0,第一次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍
(3)如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。
ArrayList为什么线程不安全?
从ArrayList的add函数看
(1)ensureCapacityInternal(size+1)方法不安全
ArrayList默认数组大小为10,假设现在已经添加进去9个元素了,size=9。
①线程A执行完add方法中的ensureCapacityInternal(size+1)挂起来
②线程B开始执行,较验数组容量发现不需要扩容。于是把“b”放在了下标为9的位置,且size自增1
③线程A接着执行,尝试把“a”放在下标为10的位置。但因为数组还没有扩容,最大下标
才为9,所以会抛出数组越界异常。
(2)elementData[size++]方法也不安全
比如刚开始添加元素时size=0,有两个线程,线程A先将元素存放到位置0,但是CPU调度线程A暂停,线程B得到运行的机会