每日面试题总结 day05
基础知识集合

1、ArrayList 和 Vector 的区别是什么?
-
这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合
- 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
- 性能:ArrayList 在性能方面要优于 Vector。
- 扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。
-
Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。
-
Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。
2、List和Set的区别:
-
List , Set 都是继承自Collection接口
-
List 特点:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。
-
Set 特点:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及TreeSet。
-
另外 List 支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。
-
Set和List
- Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
- List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
3、说一下 HashSet 的实现原理?
- HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为present,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层HashMap 的相关方法来完成,HashSet 不允许重复的值。
4、HashSet如何检查重复?HashSet是如何保证数据不可重复的?
-
向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合equles 方法比较。
-
HashSet 中的add ()方法会使用HashMap 的put()方法。
-
HashMap 的 key 是唯一的,由源码可以看出 HashSet 添加进去的值就是作为HashMap 的key,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V。所以不会重复(HashMap 比较key是否相等是先比较hashcode 再比较equals )。
-
以下是HashSet 部分源码:
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;
//创建HashSet的构造方法
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
// 调用HashMap的put方法,PRESENT是一个至始至终都相同的虚值
return map.put(e, PRESENT)==null;
}
5、hashCode()与equals()的相关规定:
- 如果两个对象相等,则hashcode一定也是相同的(hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值)
- 两个对象相等,对两个equals方法返回true
- 两个对象有相同的hashcode值,它们也不一定是相等的
- 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖
- hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。
6、说一下HashMap的实现原理?
-
HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。
-
HashMap的数据结构: 在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
-
HashMap 基于 Hash 算法实现的的
1. 当我们往HashMap中put元素时,利用key的hashCode重新hash计算出当前对象的元素在数组中的下标2. 存储时,如果出现hash值相同的key,此时有两种情况。
(1)如果key相同,则覆盖原始值
(2)如果key不同(出现冲突),则将当前的key-value放入链表中3. 获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。
4. 理解了以上过程就不难明白HashMap是如何解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对
-
需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn).
7、 为什么HashMap中String、Integer这样的包装类适合作为K?
- String、Integer等包装类的特性能够保证Hash值的不可更改性和计算准确性,能够有效的减少Hash碰撞的几率
- 都是final类型,即不可变性,保证key的不可更改性,不会存在获取hash值不同的情况
- 内部已重写了 equals() 、 hashCode() 等方法,遵守了HashMap内部的规范(不清楚可以去上面看看putValue的过程),不容易出现Hash值计算错误的情
8、 Array 和 ArrayList 有何区别?
- Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。
- Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
- Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList有。
9、TreeMap 和 TreeSet 在排序时如何比较元素?Collections 工具类中的 sort()方法如何比较元素?
-
TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进 行排 序。
-
Collections 工具类的 sort 方法有两种重载的形式
- 第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现元素的比较;
- 第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写 compare 方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java 中对函数式编程的支持)。
10、HashMap和HashTable对比
-
HashTable线程同步,HashMap非线程同步。
-
HashTable不允许<键,值>有空值,HashMap允许<键,值>有空值。
-
HashTable使用Enumeration,HashMap使用Iterator。
-
HashTable中hash数组的默认大小是11,增加方式的old*2+1,HashMap中hash数组的默认大小是16,增长方式是2的指数倍。
-
HashMap jdk1.8之前list + 链表 jdk1.8之后list + 链表,当链表长度到8时,转化为红黑树
-
HashMap链表插入节点的方式 在Java1.7中,插入链表节点使用头插法。Java1.8中变成了尾插法
-
Java1.8的hash()中,将hash值高位(前16位)参与到取模的运算中,使得计算结果的不确定性增强,降低发生哈希碰撞的概率

浙公网安备 33010602011771号