一位读者小姐姐的阿里面经分享,快被问哭了!(附部分问题详解)
这篇文章是一位 女读者 (加粗!太难得)的面试阿里的经历分享,虽然第二面就失败了,但是这样的经历对自己帮助应该还是很大的。
下面的一些问题非常具有代表性,部分问题我简单做了修改(有些问题表述的不那么准确)。这些问题对于大家用于自测或者准备面试都很有帮助。
我只给出了少部分问题的参考答案,因为自己真的抽不出有时间来把每一个问题都细心解答一遍了。单单是回答了下面的少部分问题,就从昨晚 9 点一直忙到 12 点半。
有答案需求的小伙伴,评论区安排,需要的人多的话,我这周末花时间把一份顶好的参考答案都整出来!
小声 BB:写参考答案其实挺费时间的,相比于面试的时候回答问题来说要麻烦很多。很多面试官自己问的问题可能连自己都不清楚,哈哈哈!
自我介绍就不说了,每一面都会让你说。
项目相关
这个面试前肯定要准备的,Guide 哥的文章中也提到了很多次,我准备的还算充分,面试官比较满意。
介绍一下你简历上写的项目?自己主要做了什么?(简历上虽然写了,但是面试官还是问了) 你觉得项目里给你最大的挑战是什么?遇到了什么问题?如何解决的?从中学到了什么? 项目的架构图能画一下不?(一个很 low 的后台网站) 觉得项目有哪些地方可以改进完善?(我说可以加一个 redis 缓存把热点数据缓存起来) 为什么要用 Nginx?有啥用?优缺点? 有没有遇到过内存泄漏的场景?
Java 基础
StringBuilder 和 StringBuffer(StringBuffer 是线程安全的,StringBuilder 是不安全的) 如何实现静态代理?有啥缺陷? 动态代理的作用?在哪些地方用到了?(AOP、RPC 框架中都有用到) JDK 的动态代理和 CGLIB 有什么区别? 谈谈对 Java 注解的理解,解决了什么问题? Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)?
---第 4 题参考答案---
JDK 动态代理只能只能代理实现了接口的类,而 CGLIB 可以代理未实现任何接口的类。 另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为 final 类型的类和方法。就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。
---第 5 题参考答案---
Java 语言中的类、方法、变量、参数和包等都可以注解标记,程序运行期间我们可以获取到相应的注解以及注解中定义的内容,这样可以帮助我们做一些事情。比如说 Spring 中如果检测到说你的类被 @Component
注解标记的话,Spring 容器在启动的时候就会把这个类归为自己管理,这样你就可以通过 @Autowired
注解注入这个对象了。
---第 6 题参考答案---
反射介绍:
JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。
反射的优缺点如下:
优点: 运行期类型的判断,动态加载类,提高代码灵活度。 缺点: 1,性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。2,安全问题,让我们可以动态操作改变类的属性同时也增加了类的安全隐患。
为什么框架需要反射技术?
在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。
举例:
我们在使用 JDBC 连接数据库时使用 Class.forName()
通过反射加载数据库的驱动程序;Spring 框架的 IOC(动态加载管理 Bean)创建对象以及 AOP(动态代理)功能都和反射有联系; 动态配置实例的属性; ......
更多 Java 基础相关的问题,请参考这篇顶好顶完善的文章:「Java 面试题精华集」Java 基础知识篇(2020 最新版)附 PDF 版 ! 。
集合框架
HashMap 的底层实现、JDK 1.8 的时候为啥将链表转换成红黑树?、HashMap 的负载因子、HashMap 和 Hashtable 的区别? 有哪些集合是线程不安全的?怎么解决呢? 什么是快速失败(fail-fast)、能举个例子吗?、什么是安全失败(fail-safe)呢?
集合框架相关的问题的答案,请参考这篇顶好顶完善的文章:「Java 面试题精华集」1w 字的 Java 集合框架篇(2020 最新版)附 PDF 版 ! ,里面介绍的非常详细非常棒!
多线程
在多线程情况下如何保证线程安全 synchronized 作用,底层实现 ReetrantLock 和 synchronized 的区别 AQS 线程池作用?Java 线程池有哪些参数?阻塞队列有几种?拒绝策略有几种? 线程死锁 ThreadLocal 是什么,应用场景是什么,原理是怎样的 介绍一下 Java 有哪些锁(synchronized、juc 提供的锁如 ReentrantLock、CountDownLatch、CyclicBarrier、Semaphore 等)
---第 6 题参考答案---
线程死锁描述的是这样一种情况:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态。
---第 7 题参考答案---
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢? JDK 中提供的ThreadLocal
类正是为了解决这样的问题。ThreadLocal
类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal
类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。
如果你创建了一个ThreadLocal
变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是ThreadLocal
变量名的由来。他们可以使用 get()
和 set()
方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题。
再举个简单的例子:
比如有两个人去宝屋收集宝物,这两个共用一个袋子的话肯定会产生争执,但是给他们两个人每个人分配一个袋子的话就不会出现这样的问题。如果把这两个人比作线程的话,那么 ThreadLocal 就是用来避免这两个线程竞争的。
ThreadLocal
最终的变量是放在了当前线程的 ThreadLocalMap
中,并不是存在 ThreadLocal
上,ThreadLocal
可以理解为只是ThreadLocalMap
的封装,传递了变量值。 我们可以把 ThreadLocalMap
理解为ThreadLocal
类实现的定制化的 HashMap
。ThrealLocal
类中可以通过Thread.currentThread()
获取到当前线程对象后,直接通过getMap(Thread t)
可以访问到该线程的ThreadLocalMap
对象。
每个Thread
中都具备一个ThreadLocalMap
,而ThreadLocalMap
可以存储以ThreadLocal
为 key ,Object 对象为 value 的键值对。
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
......
}
比如我们在同一个线程中声明了两个 ThreadLocal
对象的话,会使用 Thread
内部都是使用仅有那个ThreadLocalMap
存放数据的,ThreadLocalMap
的 key 就是 ThreadLocal
对象,value 就是 ThreadLocal
对象调用set
方法设置的值。
ThreadLocalMap
是ThreadLocal
的静态内部类。
JVM
讲一下 JVM 的内存结构(还问了每个区域的调优配置参数,我蒙了) Minor gc 和 Full gc 的区别,详细介绍 方法区和永久代的关系? JDK 1.8 HotSpot 的永久代为啥被彻底移除?有哪些常用参数? 主要进行 gc 的区域。永久代会发生 gc 吗?元空间呢? 各种垃圾回收算法和回收器,说出自己的理解 zgc ?zgc vs g1?(我懵逼了~我只是听过有这个东西,完全没有去了解过)
---第 2 题参考答案---
周志明先生在《深入理解 Java 虚拟机》第二版中 P92 如是写道:
“老年代 GC(Major GC/Full GC),指发生在老年代的 GC……”
上面的说法已经在《深入理解 Java 虚拟机》第三版中被改正过来了。感谢 R 大的回答:
总结:
针对 HotSpot VM 的实现,它里面的 GC 其实准确分类只有两大种:
部分收集 (Partial GC):
新生代收集(Minor GC / Young GC):只对新生代进行垃圾收集; 老年代收集(Major GC / Old GC):只对老年代进行垃圾收集。需要注意的是 Major GC 在有的语境中也用于指代整堆收集; 混合收集(Mixed GC):对整个新生代和部分老年代进行垃圾收集。
整堆收集 (Full GC):收集整个 Java 堆和方法区。
---第 3 题参考答案---
方法区也被称为永久代。很多人都会分不清方法区和永久代的关系,为此我也查阅了文献。
《Java 虚拟机规范》只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它。那么,在不同的 JVM 上方法区的实现肯定是不同的了。方法区和永久代的关系很像 Java 中接口和类的关系,类实现了接口,而永久代就是 HotSpot 虚拟机对虚拟机规范中方法区的一种实现方式。 也就是说,永久代是 HotSpot 的概念,方法区是 Java 虚拟机规范中的定义,是一种规范,而永久代是一种实现,一个是标准一个是实现,其他的虚拟机实现并没有永久代这一说法。
---第 4 题参考答案---
JDK 1.8 的时候,方法区(HotSpot 的永久代)被彻底移除了(JDK1.7 就已经开始了),取而代之是元空间,元空间使用的是直接内存。
https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace
下面是一些常用参数:
-XX:MetaspaceSize=N //设置 Metaspace 的初始(和最小大小)
-XX:MaxMetaspaceSize=N //设置 Metaspace 的最大大小
与永久代很大的不同就是,如果不指定大小的话,随着更多类的创建,虚拟机会耗尽所有可用的系统内存。
为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢?
https://plumbr.io/handbook/garbage-collection-in-java
1.整个永久代有一个 JVM 本身设置固定大小上限,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但是比原来出现的几率会更小。
当你元空间溢出时会得到如下错误:
java.lang.OutOfMemoryError: MetaSpace
你可以使用 -XX:MaxMetaspaceSize
标志设置最大元空间大小,默认值为 unlimited,这意味着它只受系统内存的限制。-XX:MetaspaceSize
调整标志定义元空间的初始大小如果未指定此标志,则 Metaspace 将根据运行时的应用程序需求动态地重新调整大小。
2.元空间里面存放的是类的元数据,这样加载多少类的元数据就不由 MaxPermSize
控制了, 而由系统的实际可用空间来控制,这样能加载的类就更多了。
3.在 JDK8,合并 HotSpot 和 JRockit 的代码时, JRockit 从来没有一个叫永久代的东西, 合并之后就没有必要额外的设置这么一个永久代的地方了。
---第 5 题参考答案---
主要进行 gc 的区域是堆,就 HotSpot 虚拟机来说,永久代会发生 gc (full gc),但是,元空间使用的是直接内存不会发生 gc。
数据库
讲一下乐观锁和悲观锁; 说一下 MVCC 说一聚簇索引和非聚簇索引的有什么不同 关于索引的各种轰炸**(索引相关的知识太重要了!!!**)
网络
为什么网络要分层? TCP/IP 4 层模型了解么? http 是哪一层的协议? http 和 https 什么区别 http2.0(不知道) tcp 三次握手过程、滑动窗口是干什么的? Mac 地址和 ip 地址的区别?既然有了 Mac 地址,为什么还要 ip 地址呢? 当你打开一个电商网站,都需要经历哪些过程? 电子邮件的发送过程?
---第 1 题参考答案---
说到分层,我们先从我们平时使用框架开发一个后台程序来说,我们往往会按照每一层做不同的事情的原则将系统分为 三层(复杂的系统分层可能会更多):
Repository(数据库操作) Service(业务操作) Controller(数据交互)
复杂的系统需要分层,因为每一层都需要专注于一类事情。我们的网络分层的原因也是一样,每一层只专注于做一类事情。
为什么计算机网络要分层呢? ,我们再来较为系统的说一说:
各层之间相互独立:各层之间相互独立,各层之间不需要关心其他层是如何实现的,只需要知道自己如何调用下层提供好的功能就可以了(可以简单理解为接口调用)。这个和我们对开发时系统进行分层是一个道理。 提高了整体灵活性 :每一层都可以使用最适合的技术来实现,你只需要保证你提供的功能以及暴露的接口的规则没有改变就行了。这个和我们平时开发系统的时候要求的高内聚、低耦合的原则也是可以对应上的。 大问题化小 :分层可以将复杂的网络间题分解为许多比较小的、界线比较清晰简单的小问题来处理和解决。这样使得复杂的计算机网络系统变得易于设计,实现和标准化。这个和我们平时开发的时候,一般会将系统功能分解,然后将复杂的问题分解为容易理解的更小的问题是相对应的,这些较小的问题具有更好的边界(目标和接口)定义。
说到计算机网络分层,我想到了计算机世界非常非常有名的一句话,这里分享一下:
计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决,计算机整个体系从上到下都是按照严格的层次结构设计的。
Guide 哥注:如果一层不够那就加两层吧!
---第 2 题参考答案---
TCP/IP 4 层模型:
应用层 传输层 网络层 网络接口层
需要注意的是,我们并不能将 TCP/IP4 层模型 和 OSI7 层模型完全精确地匹配起来,不过可以简单将两者对应起来,如下图所示:
---第 3 题参考答案---
HTTP 协议 属于应用层的协议。
HTTP 协议是基于 TCP 协议的,发送 HTTP 请求之前首先要建立 TCP 连接也就是要经历 3 次握手。目前使用的 HTTP 协议大部分都是 1.1。在 1.1 的协议里面,默认是开启了 Keep-Alive 的,这样的话建立的连接就可以在多次请求中被复用了。
另外, HTTP 协议是”无状态”的协议,它无法记录客户端用户的状态 一般我们都是通过 Session 来记录客户端用户的状态。
Spring
Spring AOP 和 IOC 的底层实现 Spring Boot 了解不?和 Spring 啥区别? Spring Boot 的启动类源码有了解过吗
其他
工作想 base 在哪里?为什么? 平时有什么兴趣爱好? 自己未来有什么规划? 平时是如何学习新技术的?(官网/书籍/博客/视频) 一般遇到问题如何解决?(Google 和 Stackoverflow,虽然我平时很少用 Stackoverflow,但是还是和面试官说我经常用,哈哈哈!) 介不介意加班?(求生欲让我回答不介意) 你有什么问题想问我?(我问了工作强度、项目上女生多不多)
总结
一定要准备好自我介绍。自我介绍尽量和简历上写的更加丰富一点,突出自己的能力。 一面主要问的是项目,所以,在面试之前一定要对项目很熟悉!项目的优化点、技术栈、架构图等等都要搞清楚。 阿里面试总体感觉比较重视基础,所以 Java 那些基本功一定要扎实。然后,网络部分也要格外重视。 阿里面试官对于一些问题问的很深入,我没有准备太好,结果导致 2 面就翻车了。
闲聊
Guide 的女读者挺少的,10 个关注我的人中只有一个女性读者。
最近在这篇文章:《最强(细)校招/社招求职指南:隔壁小姐姐已经收到字节意向书,你的秋招还没开始?》中还逮到了一个拿到的字节意向书的女读者(颜值又高,技术又好,太厉害了!),我真的不要太开心了!然后,就厚脸皮地去让这位小姐姐帮忙写一下面经(后续可能会安排上)。
还不是为了你们?我真是操碎了心啊!
我是Guide哥,Java后端开发,半个全栈,自由的少年。一个三观比主角还正的技术人。我们下期再见!