机缘巧合,其实并没有换工作的想法,却收到了微众的面试邀请,就想着去看看当是增长见识吧,因为已经好久没准备面试的事情了,而且微众毕竟作为腾讯系的看起来好像也不错。说实话那边离地铁站是真的远,不过办公环境确实很好,参照10楼的随手拍。By the way,在那边居然碰到一个大学同学,之前软件学院的,他也在面试。
废话不多说直接进入主题吧,整个过程感觉答得也不是很好,但也应该没有很差吧吧吧,全局大部分都是一些基础问题,下面根据楼主记忆罗列一下。
1.自我介绍
2.手写快速排序,冒泡排序
冒泡排序思想:相邻元素进行比较,左边元素大于右边元素则交换元素位置,这样一轮下来就会把最大的拎出来
public void bubbleSort(Integer[] arr, int n) {
if (n <= 1) return; //如果只有一个元素就不用排序了
for (int i = 0; i < n; ++i) {
// 提前退出冒泡循环的标志位,即一次比较中没有交换任何元素,这个数组就已经是有序的了
boolean flag = false;
for (int j = 0; j < n - i - 1; ++j) { //此处你可能会疑问的j<n-i-1,因为冒泡是把每轮循环中较大的数飘到后面,
// 数组下标又是从0开始的,i下标后面已经排序的个数就得多减1,总结就是i增多少,j的循环位置减多少
if (arr[j] > arr[j + 1]) { //即这两个相邻的数是逆序的,交换
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = true;
}
}
if (!flag) break;//没有数据交换,数组已经有序,退出排序
}
}
快速排序思想:选取一个基数,保证左边元素小于该基数,右边元素大于该基数。开始从右边尾部向左移动,如果发现某个数小于基数就停下来,然后左边头部开始向右移动,发现某个数大于基数停下来,交换左右两数。重复该过程。
public void quickSort(int[] arr, int start ,int end){
if (start > end){
return;
}
int i = start;
int j = end;
int temp = 0;
int guard = arr[start]; // guard为基准位
while (i < j){
// 右边元素大于基数,则一直往左移
while (arr[j] >= guard && i < j){
j--;
}
// 左边元素小于基数,则一直往右移
while (arr[i] <= guard && i < j){
i++;
}
// 交换元素
if (i < j){
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 最后将基数与i==j的位置进行交换
arr[start] = arr[i];
arr[i] = guard;
//递归调用左半数组
quickSort(arr, start, j-1);
//递归调用右半数组
quickSort(arr, j+1, end);
}
3.手写单例模式
// 线程安全的懒汉式单例
public class Singleton {
//使用volatile关键字防止重排序,因为 new Instance()是一个非原子操作,可能创建一个不完整的实例
private static volatile Singleton singleton;
private Singleton() {
}
public static Singleton getSingleton() {
// Double-Check idiom
if (singleton == null) {
synchronized (Singleton.class) { // 1
// 只需在第一次创建实例时才同步
if (singleton == null) { // 2
singleton = new Singleton(); // 3
}
}
}
return singleton;
}
}
说明:
线程 1 进入 getSingleton() 方法。
由于 singleton为 null,线程 1 在 //1 处进入 synchronized 块。
线程 1 被线程 2 预占。
线程 2 进入 getSingleton() 方法。
由于 singleton仍旧为 null,线程 2 试图获取 //1 处的锁。然而,由于线程 1 持有该锁,线程 2 在 //1 处阻塞。
线程 2 被线程 1 预占。
线程 1 执行,由于在 //2 处实例仍旧为 null,线程 1 还创建一个 Singleton 对象并将其引用赋值给 singleton。
线程 1 退出 synchronized 块并从 getInstance() 方法返回实例。
线程 1 被线程 2 预占。
线程 2 获取 //1 处的锁并检查 instance 是否为 null。
由于 instance 是非 null 的,并没有创建第二个 Singleton 对象,由线程 1 创建的对象被返回。
4.常用的集合有哪些,ArrayList与LinkedList区别
5.用过哪些设计模式?动态代理是怎么实现的
动态代理基于反射
6.SQL优化方法,explain看索引生效看的是哪几个指标
方向大体可以为:优化查询SQL,优化索引,优化数据库设计,较好的SQL优化博客
7.redis分布式锁
快速搞懂分布式锁
8.HashMap与HashTable区别,HashMap底层实现
父类不同,安全性不同。
HashMap底层是一个Entry数组,当发生hash冲突的时候,hashmap是采用链表的方式来解决的,在对应的数组位置存放链表的头结点。对链表而言,新加入的节点会从头结点加入
9.spring cloud用过吗?
springcloud是微服务架构的集大成者,将一系列优秀的组件进行了整合。基于springboot构建,对我们熟悉spring的程序员来说,上手比较容易。
通过一些简单的注解,我们就可以快速的在应用中配置一下常用模块并构建庞大的分布式系统。
SpringCloud的组件相当繁杂,拥有诸多子项目。重点关注Netflix
常用的如
服务发现——Netflix Eureka
客服端负载均衡——Netflix Ribbon
断路器——Netflix Hystrix
服务网关——Netflix Zuul
分布式配置——Spring Cloud Config
10.JDK用的哪个版本,1.7和1.8版本的HashMap实现有什么不一样
在JDK1.6,JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
11.AOP
12.多线程的实现方式
13.数据库连接池
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)