好的,这几个问题是JVM面试中的高频核心考点。下面我为你整理出适合面试回答的答案,结构清晰,重点突出。
5. JVM类加载的过程
面试官,您好。JVM的类加载过程是指将类的.class文件中的二进制数据读入到内存中,对其进行校验、解析和初始化,最终形成可以被JVM直接使用的Java类型的过程。这个过程主要分为三个大阶段,共五个小步骤:
-
加载
- 任务:通过类的全限定名获取定义此类的二进制字节流,并将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,最后在内存中生成一个代表这个类的
java.lang.Class对象,作为方法区这个类的各种数据的访问入口。 - 关键点:
- “获取二进制字节流”的方式多样,可以从ZIP包(如JAR、WAR)、网络、运行时计算生成(动态代理)、由其他文件生成(JSP)等。
- 数组类本身不通过类加载器创建,而是由JVM直接创建。
- 任务:通过类的全限定名获取定义此类的二进制字节流,并将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,最后在内存中生成一个代表这个类的
-
连接
这个阶段较为复杂,又可分为三步:-
验证
- 目的:确保Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息不会危害虚拟机自身安全。
- 主要动作:文件格式验证(魔数、版本号)、元数据验证(语义分析,如是否有父类、是否继承了final类)、字节码验证(数据流和控制流分析,确保程序语义合法)、符号引用验证(发生在解析阶段,确保解析能正常进行)。
-
准备
- 目的:为类中定义的静态变量分配内存并设置其初始零值。
- 关键点:
- 这里分配内存的仅包括类变量(被
static修饰的变量),不包括实例变量。 - 初始值是数据类型的零值,例如
int是0,boolean是false,引用类型是null。 - 如果静态变量是常量(
static final),那么在准备阶段就会被初始化为代码中指定的值,例如public static final int value = 123;在准备阶段后value就是123。
- 这里分配内存的仅包括类变量(被
-
解析
- 目的:将常量池内的符号引用替换为直接引用的过程。
- 符号引用:用一组符号来描述所引用的目标,与虚拟机内存布局无关。
- 直接引用:可以直接指向目标的指针、相对偏移量或能间接定位到目标的句柄,与虚拟机内存布局相关。
-
-
初始化
- 目的:执行类构造器
<clinit>()方法的过程,真正开始执行类中定义的Java程序代码(字节码)。 <clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的。- 触发时机:当虚拟机主动使用一个类时(如
new、调用静态方法、访问静态字段等),如果该类尚未初始化,则需要触发其初始化。
- 目的:执行类构造器
6. 类加载器
类加载器是“加载”阶段中“通过一个类的全限定名来获取描述该类的二进制字节流”这个动作的组件。JVM中内置了三个重要的类加载器:
-
启动类加载器
- 由C++实现,是JVM自身的一部分。
- 负责加载
<JAVA_HOME>/lib目录下的核心类库,或者被-Xbootclasspath参数指定的路径中的类。
-
扩展类加载器
- 由Java语言实现,是
sun.misc.Launcher$ExtClassLoader类。 - 负责加载
<JAVA_HOME>/lib/ext目录下的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。
- 由Java语言实现,是
-
应用程序类加载器
- 由Java语言实现,是
sun.misc.Launcher$AppClassLoader类。 - 负责加载用户类路径上的所有类库。如果应用程序中没有自定义类加载器,一般情况下这个就是程序中的默认类加载器。
- 由Java语言实现,是
7. 几种类加载器有什么区别
它们之间的区别主要体现在三个方面:层级关系、加载路径和父子关系。
-
层级关系(责任范围)
- 启动类加载器 处于最顶层,负责最核心的Java类库。
- 扩展类加载器 次之,负责扩展功能的类库。
- 应用程序类加载器 再次之,负责应用程序本身的类。
-
加载路径
- 启动类加载器:
<JAVA_HOME>/lib - 扩展类加载器:
<JAVA_HOME>/lib/ext - 应用程序类加载器:用户类路径
- 启动类加载器:
-
父子关系与双亲委派模型
- 这些类加载器之间的关系不是继承,而是组合。应用程序类加载器的父加载器是扩展类加载器,扩展类加载器的父加载器是启动类加载器。
- 它们之间的协作遵循 “双亲委派模型”。
- 工作过程:当一个类加载器收到加载请求时,它首先不会自己去尝试加载,而是将这个请求委派给父类加载器去完成。每一层都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器。只有当父加载器反馈自己无法完成这个加载请求(在其搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
- 双亲委派模型的好处:
- 确保Java核心库的类型安全:例如
java.lang.Object类,无论哪个类加载器要加载它,最终都委派给启动类加载器,从而保证了在整个JVM中,同一个类(由同一个类加载器加载)是唯一的,避免了核心API被篡改。 - 避免类的重复加载。
- 确保Java核心库的类型安全:例如
总结一下,它们的核心区别在于各自的职责范围和它们在双亲委派模型中扮演的不同角色,共同协作来保证Java程序的稳定运行和安全隔离。
以下是对这些技术问题的详细解答:
8、Spring @Autowired 和 @Resource
@Autowired
- Spring框架注解,默认按类型自动装配
- 配合@Qualifier可指定具体bean名称
- 默认必须存在依赖,可设置required=false
- 支持构造器、方法、字段注入
@Resource
- JSR-250标准注解,默认按名称自动装配
- 可通过name属性指定bean名称
- 名称找不到时回退到按类型装配
- 不支持构造器注入
9、@Transactional 注解
Spring的事务管理注解:
- 作用在类或方法上
- 常用属性:propagation、isolation、timeout、readOnly、rollbackFor
- 基于AOP实现,通过代理对象生效
- 默认只对RuntimeException回滚
10、死锁的定义
死锁是指两个或多个进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
必要条件:
- 互斥条件
- 请求与保持条件
- 不剥夺条件
- 循环等待条件
11、树状结构与数据权限隔离
树状结构实现:
- 邻接表模型:parent_id字段
- 路径枚举:path字段记录全路径
- 嵌套集:left、right值
- 闭包表:单独的关系表
数据权限隔离:
- 基于组织机构的权限控制
- 通过SQL拦截器自动添加WHERE条件
- 用户只能看到本机构及子机构数据
- 结合Spring Security实现
13、HashMap底层原理
JDK 1.8+:
- 数组+链表+红黑树
- 默认负载因子0.75,初始容量16
- 链表长度>8且数组长度>64时转为红黑树
- 树节点<6时退化为链表
- hash计算:(h = key.hashCode()) ^ (h >>> 16)
14、Oracle和MySQL区别
| 特性 | Oracle | MySQL |
|---|---|---|
| 收费 | 商业收费 | 开源免费 |
| 性能 | 大型企业级 | 中小型应用 |
| 存储 | 表空间管理 | 数据库=目录 |
| 并发 | 多版本读一致性 | 行级锁 |
| 分区 | 成熟分区方案 | 简单分区 |
16、数据库隔离级别区别
标准隔离级别:
- READ UNCOMMITTED
- READ COMMITTED(Oracle默认)
- REPEATABLE READ(MySQL默认)
- SERIALIZABLE
Oracle特点:
- 基于多版本并发控制
- 默认READ COMMITTED
- 提供一致性读
MySQL特点:
- 默认REPEATABLE READ
- 使用MVCC+间隙锁
- 可解决幻读问题
17、ES使用场景
- 全文搜索
- 日志分析(ELK Stack)
- 实时数据分析
- 商品搜索、内容检索
- 监控数据存储
18、Kafka架构
核心组件:
- Producer:消息生产者
- Broker:Kafka服务器节点
- Topic:消息类别
- Partition:主题分区
- Consumer:消费者
- Zookeeper:集群协调
特点:
- 高吞吐、分布式
- 消息持久化
- 副本机制保证高可用
19、Redis为什么快及高可用
快的原因:
- 基于内存操作
- 单线程避免上下文切换
- IO多路复用
- 高效数据结构
高可用方案:
- 主从复制
- 哨兵模式(Sentinel)
- 集群模式(Cluster)
20、Spring Boot与Spring Cloud区别
Spring Boot:
- 快速开发微服务
- 自动配置、起步依赖
- 嵌入式容器
- 简化配置
Spring Cloud:
- 分布式系统工具集
- 服务发现、配置管理
- 熔断器、网关
- 基于Spring Boot
21、存储过程事务与SQL事务区别
存储过程事务:
- 在存储过程内部管理
- BEGIN TRANSACTION/COMMIT/ROLLBACK
- 事务边界在存储过程中
SQL手工事务:
- 在应用代码中管理
- connection.setAutoCommit(false)
- 需要显式commit/rollback
22、MySQL MVCC & HashCode
MySQL MVCC:
- 多版本并发控制
- 通过undo log实现
- 为每个事务提供一致性视图
- 解决读写冲突
HashCode应用:
- HashMap键值定位
- 对象相等性判断
- 分布式一致性哈希
23、MySQL调优手段
代码层面:
- 避免SELECT *
- 使用预编译语句
- 合理使用索引
- 批量操作
数据库层面:
- 索引优化
- 查询缓存
- 分区表
- 参数调优
服务器层面:
- 硬件升级
- 内存配置
- 磁盘IO优化
- 连接数调整
24、Spring事务传播机制
- REQUIRED:默认,存在则加入,否则新建
- REQUIRES_NEW:新建事务,挂起当前
- SUPPORTS:存在则加入,否则非事务
- NOT_SUPPORTED:非事务执行,挂起当前
- MANDATORY:必须存在事务,否则异常
- NEVER:必须非事务,否则异常
- NESTED:嵌套事务
25、OpenFeign调优原理
- 连接池替代URLConnection
- 超时时间配置
- 启用GZIP压缩
- 日志级别控制
- 熔断器集成
- 请求拦截器优化
26、Spring Boot常用注解
核心注解:
- @SpringBootApplication
- @RestController
- @RequestMapping
- @Autowired
- @Component, @Service, @Repository
配置相关:
- @Configuration
- @Bean
- @Value
- @ConfigurationProperties
其他:
- @Transactional
- @Async
- @Scheduled
- @Profile
这些答案涵盖了各个问题的核心要点,可以根据具体面试情况进行详细展开说明。