现在很多面试官喜欢把jvm和jmm的知识都放进java基础来进行面试,后面我写一个专门的专题用来写jvm的东西,目前我们说的java基础基本就是集合,IO,多线程,目前问IO的基本上已经很少了,多的是问NIO这种的,下面主要写的是关于集合方面的:
ArrayList和LinkedList区别?
问题回答:
1.都是List接口的实现类
2.ArrayList基于数组,LinkedList基于链表
3.ArrayList
查询快,增删慢
往数组尾部添加元素的效率高,也就是调用add(obj),但是还是比LinkedList慢。
4.LinkedList
数据添加删除效率高,只需要改变指针指向即可
查询数据的平均效率低,需要对链表进行遍历
ArrayList扩容机制怎样?
问题回答:
1.ArrayList每次扩容是原来的1.5倍。
2.数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。
3.代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。尽可能,就指定其容量,以避免数组扩容的发生。
4.创建方式方式不同,容量不同
断点看扩容情况1 List arrayList = new ArrayList();
public class TestArrayList {
2
public static void main(String[] args) {
3
List<Integer> list = new ArrayList<>();
4
5
for (int i = 1; i <= 20; i++) {
6
if (i == 1) {
7
System.out.println("断点位置 没添加元素时候容量 0");
8
}
9
list.add(i);
10
if (i == 1) {
11
System.out.println("断点位置 第一次添加元素 容量 10");
12
}
13
if (i == 11) {
14
System.out.println("断点位置 第1次扩容 容量 15");
15
}
16
if (i == 16) {
17
System.out.println("断点位置 第2次扩容 容量15*1.5= 22.5,22 or 23 ");
18
}
19
}
20
}
21
}
断点看扩容情况2
public class TestArrayList1 {
2
public static void main(String[] args) {
3
List<Integer> list = new ArrayList<>(4);
4
5
for (int i = 1; i <= 20; i++) {
6
if (i == 1) {
7
System.out.println("断点位置 没添加元素时候容量 4");
8
}
9
list.add(i);
10
if (i == 5) {
11
System.out.println("断点位置 第一次扩容 容量 6 ");
12
}
13
if (i == 7) {
14
System.out.println("断点位置 第二次扩容 容量9");
15
}
16
}
17
}
18
}
HashMap和HashTable的区别?
问题回答:
1.HashMap采用了数组+链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改
2.HashMap是非synchronized,所以HashMap比HashTable更快
3.HashMap可以接受null键和值,而Hashtable则不能(原因就是equlas()方法需要对象,因为HashMap是后出的API经过处理才可以)
HashMap的工作原理?
简要回答:
- HashMap 的存储机制
1.在 Java 1.8 中,如果链表的长度超过了 8 ,那么链表将转化为红黑树;链表长度低于6,就把红黑树转回链表; - Java 1.8 中 HashMap 的不同
1.在 Java 1.8 中,如果链表的长度超过了 8 ,那么链表将转化为红黑树;链表长度低于6,就把红黑树转回链表;
2.发生 hash 碰撞时,Java 1.7 会在链表头部插入,而 Java 1.8 会在链表尾部插入;
3.在 Java 1.8 中,Entry 被 Node 代替(换了一个马甲)。
ps:关于hashmap这一块的原理网上很多,这里只做面试题回答
拓展链接
问题回答: - HashMap 的存储机制
a.在 Java 1.8 中,如果链表的长度超过了 8 ,那么链表将转化为红黑树;链表长度低于6,就把红黑树转回链表; - Java 1.8 中 HashMap 的不同
a.在 Java 1.8 中,如果链表的长度超过了 8 ,那么链表将转化为红黑树;链表长度低于6,就把红黑树转回链表;
b.发生 hash 碰撞时,Java 1.7 会在链表头部插入,而 Java 1.8 会在链表尾部插入;
c.在 Java 1.8 中,Entry 被 Node 代替(换了一个马甲)。 - put过程
a.对Key求Hash值,然后再计算下标
b.如果没有碰撞,直接放入桶中(碰撞的意思是计算得到的Hash值相同,需要放到同一个bucket中)
c.如果碰撞了,以链表的方式链接到后面
d.如果链表长度超过阀值( TREEIFY THRESHOLD==8),就把链表转成红黑树,链表长度低于6,就把红黑树转回链表
e.如果节点已经存在就替换旧值
f.如果桶满了(容量16*加载因子0.75),就需要 resize(扩容2倍后重排) - get过程
-a.当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置
-b.找到bucket位置之后,会调用keys.equals()方法去找到链表中正确的节点
-c.最终找到要找的值对象
List、Set、Map三个接口的区别以及常见子类?
- List、Set单列,Map是双列的键值对
- List可重复,set不可重复
- List有序的,set是无序
- List中最常用的两个子类:ArrayList(基于数组,查询快)和LinkedList(基于链表,增删快)
- Set中最常用的两个子类:HashSet和TreeSet
- Map中最常用的两个子类:HashMap和TreeMap
ps:说道集合我们需要去了解JUC并发包底下的那些集合
- 例如:hashmap是否是线程安全的,如何解决线程不安全问题
- 是否了解ConcurrentHashMap
- 是否了解CopyOnWriteArrayList
这只是给大家举了一些例子,大家可以往这方面看
说下ConcurrentHashMap ?
问题回答:
- 在ConcurrentHashMap中,无论是读操作还是写操作都能保证很高的性能
- 在进行读操作时(几乎)不需要加锁,而在写操作时通过锁分段技术只对所操作的段加锁而不影响客户端对其它段的访问。
- 在理想状态下,ConcurrentHashMap 可支持16个线程执行并发写操作,及任意数量线程的读操作。
- 关于它的存储结构
a.JDK 1.7 中使用分段锁(ReentrantLock + Segment + HashEntry),相当于把一个 HashMap 分成多个段,每段分配一把锁,这样支持多线程访问。锁粒度:基于 Segment,包含多个 HashEntry。
b.JDK 1.8 中使用 CAS + synchronized + Node + 红黑树。锁粒度:Node(首结点)(实现 Map.Entry<K,V>)。锁粒度降低了