牛客上刷到一条关于比亚迪学历和定级的帖子,感觉对想去比亚迪的同学有很大的参考价值,同步过来大家看一眼。
不知道大家 get 到了什么信息,反正我 get 到的是:
对于学历高、能力一般的人来说是个捡漏的机会
。
没错,我就是那个学历一般、能力也一般的人,😆,不知道比亚迪是否对我有意向哈~
对于 23 届的同学来说,比亚迪可以说是秋招的神,挽救了不知多少同学的就业需求。所以,站在我的角度,只要招人、给钱、不毁约,就是好公司(dog)
希望今年秋招的时候,比亚迪能继续加大招聘的力度哈,这样 25 届的同学最起码可以保个底(嗯嗯,给大家磕头许愿啦)
讲真,比亚迪的面试相对很多大厂也友好得多,我们这里就以《Java 面试指南》中同学 3 的 Java 一面为例,来看看比亚迪的面试官都喜欢问哪些题目,好做到心中有数。
看了一眼,Java 基础 4 道题,MySQL 1道题,计算机网络 1 道题,Spring 全家桶 2 道题,果然还是离不开我一直强调的 Java 后端四大件 Java 基础,大家在准备学习的时候一定要心中有数。
内容较长,撰写硬核面经不容易,建议大家先收藏起来,面试的时候大概率会碰到,我会尽量用通俗易懂+手绘图的方式,让你能背会的同时,还能理解和掌握,总之:让天下所有的面渣都能逆袭 😂
计算机网络
说一下 HTTP 的结构和 HTTPS 的原理
HTTP 的报文结构可以分为两类:请求报文和响应报文。两者在结构上相似,都包含了
起始行
、
头部
和
消息正文
。
三分恶面渣逆袭:HTTP 报文
说下 HTTP 请求报文结构?
GET /index.html HTTP/1.1
Host: www.javabetter.cn
Accept: text/html
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3
①、请求行
包括方法(如 GET、POST)、请求的 URL 和 HTTP 协议的版本。例如:
GET /index.html HTTP/1.1
。
②、请求头部
包含请求的附加信息,如客户端想要接收的内容类型、浏览器类型等。
请求头部由键值对组成,键和值之间用冒号分隔,每一行一个键值对。例如:
-
Host: www.javabetter.cn
,表示请求的主机名(域名)
-
Accept: text/html
,表示客户端可以接收的媒体类型
-
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3
,表示客户端的浏览器类型
③、空行
请求头部和消息正文之间有一个空行,表示请求头部结束。
④、消息正文(可选)
请求的具体内容,如 POST 请求中的表单数据;GET 请求中没有消息正文。
说下 HTTP 响应报文结构?
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
沉默王二很天真
①、状态行
包括 HTTP 协议的版本、状态码(如 200、404)和状态消息(如 OK、NotFound)。例如:
HTTP/1.0 200 OK
。
②、响应头部
包含响应的附加信息,如服务器类型、内容类型、内容长度等。也是键值对,例如:
-
Content-Type: text/plain
,表示响应的内容类型
-
Content-Length: 137582
,表示响应的内容长度
-
Expires: Thu, 05 Dec 1997 16:00:00 GMT
,表示资源的过期时间
-
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
,表示资源的最后修改时间
-
Server: Apache 0.84
,表示服务器类型
③、空行
表示响应头部结束。
④、消息正文(可选)
响应的具体内容,如 HTML 页面。不是所有的响应都有消息正文,如 204 No Content 状态码的响应。
说一下 HTTPS 的原理
使用 HTTPS 主要是为了解决 HTTP 传输过程中的一些安全问题,因为 HTTP 是明文传输,所以 HTTPS 在 HTTP 的基础上加入了 SSL/TLS 协议。
三分恶面渣逆袭:HTTP 和 HTTPS
SSL(安全套接字)/TLS(传输层安全)协议可以用来加密通信内容,保证通信过程中的数据不被窃取和篡改。整个加密过程主要涉及两种类型的加密方法:
-
非对称加密:服务器向客户端发送公钥,然后客户端用公钥加密自己的随机密钥,也就是会话密钥,发送给服务器,服务器用私钥解密,得到会话密钥。
-
客户端会通过数字证书来验证服务器的身份,数字证书由 CA(证书权威机构)签发,包含了服务器的公钥、证书的颁发机构、证书的有效期等信息。
三分恶面渣逆袭:HTTPS 主要流程
HTTPS 主要解决了以下几个问题:
-
窃听风险
:第三方可以截获传输的数据包,获取敏感信息。
-
篡改风险
:第三方可以在传输过程中篡改数据包,修改数据。
-
Java基础(包括JVM和并发编程)
对象创建到销毁的流程
当我们使用 new 关键字创建一个对象的时候,JVM 首先会检查 new 指令的参数是否能在常量池中定位到一个类的符号引用,然后检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,就先执行相应的类加载过程。
如果已经加载,JVM 会为新生对象分配内存,内存分配完成之后,JVM 将分配到的内存空间初始化为零值(成员变量,数值类型是0,布尔类型是false,对象类型是null),接下来设置对象头,对象头里包含了对象是哪个类的实例、对象的哈希码、对象的 GC 分代年龄等信息。
最后,JVM 会执行构造方法(
),将成员变量赋值为预期的值,这样一个对象就创建完成了。
对象的销毁过程了解吗?
对象创建完成后,就可以通过引用来访问对象的方法和属性,当对象不再被任何引用指向时,对象就会变成垃圾。
垃圾收集器会通过可达性分析算法判断对象是否存活,如果对象不可达,就会被回收。
垃圾收集器会通过标记清除、标记复制、标记整理等算法来回收内存,将对象占用的内存空间释放出来。
常用的垃圾收集器有 CMS、G1、ZGC 等,它们的回收策略和效率不同,可以根据具体的场景选择合适的垃圾收集器。
介绍一下 JVM 运行时数据区
JVM 的内存区域,有时也叫 JVM 运行时数据区,可以粗暴地划分为
堆
和
栈
,当然了,按照 Java 的虚拟机规范,可以再细分为
程序计数器
、
虚拟机栈
、
本地方法栈
、
堆
、
方法区
等。
三分恶面渣逆袭:Java虚拟机运行时数据区
其中
方法区
和
堆
是线程共享的,
虚拟机栈
、
本地方法栈
和
程序计数器
是线程私有的。
介绍一下程序计数器?
程序计数器(Program Counter Register)也被称为 PC 寄存器,是一块较小的内存空间。它可以看作是当前线程所执行的字节码行号指示器。
介绍一下 Java 虚拟机栈?
Java 虚拟机栈(Java Virtual Machine Stack),通常指的就是“栈”,它的生命周期与线程相同。
当线程执行一个方法时,会创建一个对应的栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,然后栈帧会被压入栈中。当方法执行完毕后,栈帧会从栈中移除。
三分恶面渣逆袭:Java虚拟机栈
介绍一下本地方法栈?
本地方法栈(Native Method Stacks)与虚拟机栈相似,区别在于虚拟机栈是为 JVM 执行 Java 编写的方法服务的,而本地方法栈是为 Java 调用本地(native)方法服务的,由 C/C++ 编写。
介绍一下 Java 堆?
堆(heap)是 JVM 中最大的一块内存区域,被所有线程共享,在 JVM 启动时创建,主要用来存储对象的。
以前,Java 中“几乎”所有的对象都会在堆中分配,但随着 JIT 编译器的发展和逃逸技术的逐渐成熟,“所有的对象都会分配到堆上”就不再那么绝对了。
从 JDK 7 开始,JVM 已经默认开启逃逸分析了,意味着如果某些方法中的对象引用没有被返回或者未被方法体外使用(也就是未逃逸出去),那么对象可以直接在栈上分配内存。
堆也是垃圾收集器管理的目标区域,因此一些资料中也会把 Java 堆称作“GC 堆”(Garbage Collected Heap)。
从内存回收的角度来看,由于垃圾收集器大部分都是基于分代收集理论设计的,所以堆也会被划分为
新生代
、
老年代
、
Eden空间
、
From Survivor空间
、
To Survivor空间
等。
三分恶面渣逆袭:Java 堆内存结构
介绍一下方法区?
方法区并不真实存在,属于 Java 虚拟机规范中的一个逻辑概念,用于存储已被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等。
在 HotSpot 虚拟机中,方法区的实现称为永久代(PermGen),但在 Java 8 及之后的版本中,已经被元空间(Metaspace)所替代。
BIO NIO 的区别
BIO(Blocking I/O):采用阻塞式 I/O 模型,线程在执行 I/O 操作时被阻塞,无法处理其他任务,适用于连接数较少的场景。
NIO(New I/O 或 Non-blocking I/O):采用非阻塞 I/O 模型,线程在等待 I/O 时可执行其他任务,通过 Selector 监控多个 Channel 上的事件,适用于连接数多但连接时间短的场景。
简单说一下 BIO?
BIO,也就是传统的 IO,基于字节流或字符流(如 FileInputStream、BufferedReader 等)进行文件读写,基于 Socket 和 ServerSocket 进行网络通信。
对于每个连接,都需要创建一个独立的线程来处理读写操作。
三分恶面渣逆袭:BIO
简单说下 NIO?
NIO,JDK 1.4 时引入,放在 java.nio 包下,提供了 Channel、Buffer、Selector 等新的抽象,基于 RandomAccessFile、FileChannel、ByteBuffer 进行文件读写,基于 SocketChannel 和 ServerSocketChannel 进行网络通信。
实际上,“旧”的 I/O 包已经使用 NIO 重新实现过,所以在进行文件读写时,NIO 并无法体现出比 BIO 更可靠的性能。
NIO 的魅力主要体现在网络编程中,服务器可以用一个线程处理多个客户端连接,通过 Selector 监听多个 Channel 来实现多路复用,极大地提高了网络编程的性能。
三分恶面渣逆袭:NIO
缓冲区 Buffer 也能极大提升一次 IO 操作的效率。
三分恶面渣逆袭:NIO完整示意图
说一下 JMM
Java 内存模型(Java Memory Model)是一种抽象的模型,简称 JMM,主要用来定义多线程中变量的访问规则,用来解决变量的可见性、有序性和原子性问题,确保在并发环境中安全地访问共享变量。
三分恶面渣逆袭:Java内存模型
JMM 定义了线程内存和主内存之间的抽象关系:线程之间的共享变量存储在
主内存
(Main Memory)中,每个线程都有一个私有的
本地内存
(Local Memory),本地内存中存储了共享变量的副本,用来进行线程内部的读写操作。
-
当一个线程更改了本地内存中共享变量的副本后,它需要将这些更改刷新到主内存中,以确保其他线程可以看到这些更改。
-
当一个线程需要读取共享变量时,它可能首先从本地内存中读取。如果本地内存中的副本是过时的,线程将从主内存中重新加载共享变量的最新值到本地内存中。
本地内存是 JMM 中的一个抽象概念,并不真实存在。实际上,本地内存可能对应于 CPU 缓存、寄存器或者其他硬件和编译器优化。
三分恶面渣逆袭:实际线程工作模型
对于一个双核 CPU 的系统架构,每个核都有自己的控制器和运算器,其中控制器包含一组寄存器和操作控制器,运算器执行算术逻辅运算。
每个核都有自己的一级缓存,在有些架构里面还有一个所有 CPU 共享的二级缓存。
Java 内存模型里面的本地内存,可能对应的事 L1 缓存或者 L2 缓存或者 CPU 寄存器。
Spring全家桶(包括Spring Boot)
说一下 Spring Boot 的自动装配原理
在 Spring 中,自动装配是指容器利用反射技术,根据 Bean 的类型、名称等自动注入所需的依赖。
在 Spring Boot 中,开启自动装配的注解是
@EnableAutoConfiguration
。
二哥的 Java 进阶之路
Spring Boot 为了进一步简化,直接通过
@SpringBootApplication
注解一步搞定,这个注解包含了
@EnableAutoConfiguration
注解。