简单的一个电话面试,很基础,但是回答的不是很好,总结一下。
Java:
1.hashtable、hashmap和concurrenthashmap的区别(线程安全问题,hashtable如何实现同步的)
1)hashtable:
- 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
- 初始大小为11,扩容:newsize = olesize*2+1
2)hashmap:
- 底层数组+链表实现,可以存储null键和null值,线程不安全
- 初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
hashtable在它的很多方法中都添加了synchronized关键字。
2.hashmap和hashset的区别
*HashMap* | *HashSet* |
HashMap实现了Map接口 | HashSet实现了Set接口 |
HashMap储存键值对 | HashSet仅仅存储对象 |
使用put()方法将元素放入map中 | 使用add()方法将元素放入set中 |
HashMap中使用键对象来计算hashcode值 | HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false |
HashMap比较快,因为是使用唯一的键来获取对象 | HashSet较HashMap来说比较慢 |
3.arraylist和linkedlist的区别、复杂度
- ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于双向链表的数据结构
- 对于随机访问,ArrayList要优于LinkedList,因为LinkedList要移动指针
- 对于插入和删除,LinkedList较占优势,ArrayList要移动数据。
- ArrayList和LinkedList都是非线程安全的容器
ArrayList 是线性表(数组)
get() 直接读取第几个下标,复杂度 O(1)
add(E) 添加元素,直接在后面添加,复杂度O(1)
add(index, E) 添加元素,在第几个元素后面插入,后面的元素需要向后移动,复杂度O(n)
remove()删除元素,后面的元素需要逐个移动,复杂度O(n)
LinkedList 是链表的操作
get() 获取第几个元素,依次遍历,复杂度O(n)
add(E) 添加到末尾,复杂度O(1)
add(index, E) 添加第几个元素后,需要先查找到第几个元素,直接指针指向操作,复杂度O(n)
remove()删除元素,直接指针指向操作,复杂度O(1)
4.hash冲突以及解决方法
hashcode()的方法是为了产生不同的hash值,但是当两个对象的hash一样时,就发生了hash冲突。
解决方法:
①:开放地址法;
②:再hash的方法;
③:拉链法;
④:建立公共溢出区法;
5.单例模式
饿汉模式:
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。
缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。
饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题,
懒汉模式:
//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//静态工厂方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
MapReduce:
1.解释一下数据倾斜?mapreduce阶段数据倾斜解决方法
2.mapreduce shuffle阶段
3.二次排序
4.mapreduce分区阶段 默认的分区方法