小米(实习一面)

  1. HashMap的底层实现原理是什么?jdk8做了哪些优化?

  2. 线程状态有哪些?他们是如何工作的?

  3. springboot有哪些优点?它和spring有什么区别?

  4. 列举你知道的设计模式,分别对应的应用场景有哪些?

  5. 对分布式有了解么?什么是分布式?有哪些实现方式?如何实现?

  6. 求二叉树的深度

  7. 二分查找

  8. 快速排序

  9. 冒泡排序


我的面经:

  1. HashMap的底层实现原理是什么?jdk8做了哪些优化?
    在 JDK 1.7 中 HashMap 是以数组加链表的形式组成的,JDK 1.8 之后新增了红黑树的组成结构,当链表大于 8 并且容量大于 64 时,链表结构会转换成红黑树结构。
    JDK 1.8 之所以添加红黑树是因为一旦链表过长,会严重影响 HashMap 的性能,而红黑树具有快速增删改查的特点,这样就可以有效的解决链表过长时操作比较慢的问题。

上面介绍了 HashMap 的组成结构,但面试官想要知道的远远不止这些,和 HashMap 相关的面试题还有以下几个:

JDK 1.8 HashMap 扩容时做了哪些优化?

加载因子为什么是 0.75?

当有哈希冲突时,HashMap 是如何查找并确认元素的?

HashMap 源码中有哪些重要的方法?

HashMap 是如何导致死循环的?

  1. 线程状态有哪些?他们是如何工作的?

线程的状态在 JDK 1.5 之后以枚举的方式被定义在 Thread 的源码中,它总共包含以下 6 个状态:
NEW,新建状态,线程被创建出来,但尚未启动时的线程状态;
RUNNABLE,就绪状态,表示可以运行的线程状态,它可能正在运行,或者是在排队等待操作系统给它分配 CPU 资源;
BLOCKED,阻塞等待锁的线程状态,表示处于阻塞状态的线程正在等待监视器锁,比如等待执行 synchronized 代码块或者使用 synchronized 标记的方法;
WAITING,等待状态,一个处于等待状态的线程正在等待另一个线程执行某个特定的动作,比如,一个线程调用了 Object.wait() 方法,那它就在等待另一个线程调用 Object.notify() 或 Object.notifyAll() 方法;
TIMED_WAITING,计时等待状态,和等待状态(WAITING)类似,它只是多了超时时间,比如调用了有超时时间设置的方法 Object.wait(long timeout) 和 Thread.join(long timeout) 等这些方法时,它才会进入此状态;
TERMINATED,终止状态,表示线程已经执行完成。

线程的工作模式是,首先先要创建线程并指定线程需要执行的业务方法,然后再调用线程的 start() 方法,此时线程就从 NEW(新建)状态变成了 RUNNABLE(就绪)状态,此时线程会判断要执行的方法中有没有 synchronized 同步代码块,如果有并且其他线程也在使用此锁,那么线程就会变为 BLOCKED(阻塞等待)状态,当其他线程使用完此锁之后,线程会继续执行剩余的方法。

考点分析
线程一般会作为并发编程的起始问题,用于引出更多的关于并发编程的面试问题。当然对于线程的掌握程度也决定了你对并发编程的掌握程度,通常面试官还会问:

BLOCKED(阻塞等待)和 WAITING(等待)有什么区别?
start() 方法和 run() 方法有什么区别?
线程的优先级有什么用?该如何设置?
线程的常用方法有哪些?

知识扩展
BLOCKED 和 WAITING 的区别
虽然 BLOCKED 和 WAITING 都有等待的含义,但二者有着本质的区别,首先它们状态形成的调用方法不同,其次 BLOCKED 可以理解为当前线程还处于活跃状态,只是在阻塞等待其他线程使用完某个锁资源;而 WAITING 则是因为自身调用了 Object.wait() 或着是 Thread.join() 又或者是 LockSupport.park() 而进入等待状态,只能等待其他线程执行某个特定的动作才能被继续唤醒,比如当线程因为调用了 Object.wait() 而进入 WAITING 状态之后,则需要等待另一个线程执行 Object.notify() 或 Object.notifyAll() 才能被唤醒

  1. springboot有哪些优点?它和spring有什么区别?

作为 Java 开发人员对 Spring 框架都很熟悉,Spring 为 Java 程序提供了全面的基础架构支持,包含了很多非常实用的功能,如 Spring JDBC、Spring AOP、Spring ORM、Spring Test 等,这些模块的出现,大大的缩短了应用程序的开发时间,同时提高了应用开发的效率。

Spring Boot 本质上是 Spring 框架的延伸和扩展,它的诞生是为了简化 Spring 框架初始搭建以及开发的过程,使用它可以不再依赖 Spring 应用程序中的 XML 配置,为更快、更高效的开发 Spring 提供更加有力的支持。

Spring Boot 本质上是 Spring 的延伸,它是基于 Spring 的,它为快速构建和开发 Spring 提供了有力的支撑; Spring Boot 的四大特性:更快速的构建能力、起步依赖、内嵌容器支持、Actuator 监控支持等。

  1. 列举你知道的设计模式,分别对应的应用场景有哪些?

设计模式的五个原则solid
S - 单一职责原则:
O - 开放封闭原则:
L - Liskov原则:
I - 接口隔离原则:
D – 依赖倒置原则:

单例模式
何为单例?单一实例。全局只有一个。
•哪些场合需要用到单例?Servlet、ServletContext
从应用程序中取出的实例始终是同一个。 孤本
好处:节约资源

单例模式是指一个类在运行期间始终只有一个实例,我们把它称之为单例模式。

单例模式的典型应用场景是 Spring 中 Bean 实例,它默认就是 singleton 单例模式。

单例模式的优点很明显,可以有效地节约内存,并提高对象的访问速度,同时避免重复创建和销毁对象所带来的性能消耗,尤其是对频繁创建和销毁对象的业务场景来说优势更明显。然而单例模式一般不会实现接口,因此它的扩展性不是很好,并且单例模式违背了单一职责原则,因为单例类在一个方法中既创建了类又提供类对象的复合操作,这样就违背了单一职责原则,这也是单例模式的缺点所在。

工厂模式
作用是生产实例,工厂要提供create方法。
通过工厂可以把实例的实例化细节隐藏起来。
XXXFactory的时候,就是获得xxx实例的。当看到类名是XXXFactory的时候,就要意识到这是一个工厂的设计模式。

  1. 对分布式有了解么?什么是分布式?有哪些实现方式?如何实现?

- 分布式系统一定是由多个节点组成的系统。

其中,节点指的是计算机服务器,而且这些节点一般不是孤立的,而是互通的。

- 这些连通的节点上部署了我们的节点,并且相互的操作会有协同。

分布式系统对于用户而言,他们面对的就是一个服务器,提供用户需要的服务而已。而实际上这些服务是通过背后的众多服务器组成的一个分布式系统。因此分布式系统看起来像是一个超级计算机一样。

例如淘宝,平时大家都会使用,它本身就是一个分布式系统。我们通过浏览器访问淘宝网站时,这个请求的背后就是一个庞大的分布式系统在为我们提供服务,整个系统中有的负责请求处理,有的负责存储,有的负责计算,最终他们相互协调把最后的结果返回并呈现给用户。


编程题:

  1. 求二叉树的深度

  2. 二分查找

  3. 快速排序

  4. 冒泡排序

public static void BubbleSort(int[] nums) {
	boolean flag = true;
	int temp;
	for(int j = nums.length - 1; j > 0; j--) {
		flag = false;
		for(int i = 0; i < j; i++){
			if(nums[i] < nums[i+1]) {
				temp = nums[i];
				nums[i] = nums[j];
				nums[j] = temp;
			}
			flag = true;
		}
		if(!flag) break;
	}
}
  1. 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。

说明:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。

示例:

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3

输出:[1,2,2,3,5,6]

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        //小米实习一面
        int i = m - 1, j = n - 1;
        for(int k = m + n - 1; i >= 0 && j >= 0; k--){
            if(nums1[i] < nums2[j]) 
                nums1[k] = nums2[j--];
            else 
                nums1[k] = nums1[i--];
        }
        if(j >= 0){
            for(int x = 0; x <= j; x++){
                nums1[x] = nums2[x];
            }
        }
    }
}
匿名

发表评论

匿名网友