鱼友9534
Java后端
·2024-04-26
很多小伙伴想要小米一面的面经,因此他来啦~ # 1. 堆和栈的区别? - 堆 是JVM中 几乎所有对象存放的地方,会存放 创建的对象实例和数组。为什么说是所有的对象,是因为有些对象直接是在栈上分配,就是一些经过JVM逃逸分析之后,未被外部方法所引用的对象; - 堆也是一个JVM进程中所有资源共享的区域,因此会存在线程安全问题,JVM的垃圾回收的区域也主要是在java堆中 - 栈是 每个线程运行时 所需要的内存空间,栈由多个栈帧组成,对应着每次方法调用时所占用的内存 - 栈帧里面保存着方法的返回值、局部变量、返回地址;当前执行的方法被称为活动栈帧 - 虚拟机栈是线程私有的,因此是线程安全的 # 2. 堆和栈谁的效率高? - 申请速度快:栈是**程序运行前**就已经分配好的空间,所以运行时分配几乎不需要时间。 - 而堆是运行时动态申请的,相当于将分配内存的耗时由编译阶段转嫁到了机器运行阶段,将分配过程从编译器搬到了运行的代码中。 - 于是动态分配的速度不仅与分配算法有关,还与机器运行速度有关。(栈是编译时分配空间,而堆是动态分配(运行时分配空间),所以栈的申请速度快) - 存储寻址速度快:**栈的物理地址空间是连续的,而堆未必**,查找堆的链表也会耗费较多时间,所以存储寻址速度慢。 - CPU硬件操作速度快:cpu有专门的寄存器(esp,ebp)来操作栈,堆是使用间接寻址的,所以栈快。 # 3. 介绍一下快速排序的原理 **快排思想:** - 通过筛选一个基准元素,将待排序列分隔为两个子序列; - 然后对子序列进行排序,使左子序列的元素小于基准元素,使右子序列的元素大于基准元素 - 之后继续对子序列进行排序,直到使整个序列有序 **流程:** - 先为序列 设定一个 基准元素,一般是选择第一个元素,然后设置两个前后指针 - 先从右指针开始,如果右指针的元素 小于 基准元素,则将该元素 移动至 左指针位置,然后左指针 - 如果右指针的元素 大于 基准元素,则该元素不动,右指针--,继续判断该元素是否 小于 基准元素 - 若右指针的元素移动到 左指针,然后左指针 ,继续判断该元素是否 大于 基准元素 # 4. Java中线程有哪些状态? **六种状态**: 1. **初始(NEW)**:新创建了一个线程对象,但**还没有调用start()方法。** 2. **运行(RUNNABLE)**:Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。 线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。 3. **阻塞(BLOCKED)**:表示线程阻塞于锁。 4. **等待(WAITING)**:进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。 5. **超时等待(TIMED_WAITING)**:该状态不同于WAITING,它可以在指定的时间后自行返回。 6. **终止(TERMINATED)**:表示该线程已经执行完毕。 # 5. 在Java中怎么去保证多线程运行安全? **三种保证线程安全的方法:** 1. **synchronized** 关键字,实现一个 同步代码块 或 同步方法 2. **Lock锁机制**, 通过创建Lock对象,采用lock()加锁,unlock()解锁,来保护指定的代码块 3. **AtomicInteger原子类**,juc包下的保证原子性的操作类 # 6. 什么是AOP? - AOP 是一种 **面向切面编程** 的思想,让我们能够在不修改源码的情况下 **给程序动态地进行功能增强**,实现功能解耦 - 可以针对于方法切面,去做一个功能的动态增强 - AOP 是基于 动态代理去实现的,因此我们可以针对 方法(切面)进行 前置、后置、环绕、异常通知 **AOP使用场景:** - 记录日志 (调用方法后记录日志) - **权限控制** (调用方法前校验是否有权限):OJ项目中使用了 @AuthCheck - **监控性能** (统计方法运行时间) - **事务管理** (调用方法前开启事务,调用方法后提交关闭事务 ) > Spring的事务中底层也是基于AOP动态代理去实现的,采用的是Cglib动态代理实现的,通过 **继承被代理类** > 所以事务失效的原理其实和AOP息息相关,例如事务的异常在方法内部手动捕获,就会造成事务失效,需要向上抛,才能被aop捕获; > 例如 非public方法事务失效,因为cglib代理是继承被代理类去实现的,需要重写父类需要被增强的方法,如果父类private就不能代理 > # 7. 在SpringBoot的启动类当中,有用到哪些注解? - ComponentScan 默认扫描该类所在包及其子包 - SpringBootConfiguration 里面的注解其实就是 Configuration 配置注解 - EnableAutoConfiguration 自动配置的核心注解 - **@AutoConfigurationPackage** - **@Import({AutoConfigurationImportSelector.class})** 其内部就是读取了 **该项目和该项目引用Jar包** 的 classpath 路径下 `META-INF/Spring.factories` 的 配置类 然后这些配置类会根据 **条件注解所 指定的条件来**判断 是否将该类加载进 Spring容器 - Spring 2.x 自动配置文件 是在 `META-INF/Spring.factories` - Spring 3.x 是在`META-INF/spring` 文件夹内 的一个 **autoconfigure** 中 例如 `org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration` 其中会根据 `@ConditionalOnxx` 来判断是否要加载 某个类进容器 ```java @AutoConfiguration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "redisTemplate") @ConditionalOnSingleCandidate(RedisConnectionFactory.class) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean @ConditionalOnSingleCandidate(RedisConnectionFactory.class) public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { return new StringRedisTemplate(redisConnectionFactory); } } ``` # 8. 说说事务的特性? - 原子性:对数据库进行的一组操作视为原子的,要么全部成功,要么全部失败 - 一致性:数据库总是从一个一致性的状态转换到另一个一致性的状态 - 隔离性:一个事务所做的修改操作在提交事务之前,对于其他事务来说是不可见的 - 持久性:一旦事务提交,则其所做的修改会永久保存到数据库 # 9. MYSQL 的索引不适合用在什么场景中? 首先可以先明确,什么时候适合使用索引? - 对于查询比较频繁的字段,改和删的操作比较少 - 经常作为查询条件的字段 - 字段的区分度比较高 因此不适合用在: - 增、删、改操作比较频繁的字段 - 字段的区分度比较低,例如isDelete # 10. L322 零钱兑换 给你一个整数数组 `coins` ,表示不同面额的硬币;以及一个整数 `amount` ,表示总金额。 计算并返回可以凑成总金额所需的 **最少的硬币个数** 。如果没有任何一种硬币组合能组成总金额,返回 `-1` 。 你可以认为每种硬币的数量是无限的。 **示例 1:** **输入:coins = `[1, 2, 5]`, amount = `11` 输出:**`3` **解释:11 = 5 5 1 **示例 2:** **输入:coins = `[2]`, amount = `3` 输出:**-1 **示例 3:** **输入:coins = [1], amount = 0 输出:0 ```java public int coinChange(int[] coins, int amount) { int[] dp = new int[amount 1]; Arrays.fill(dp, amount 1); dp[0] = 0; for (int i = 1; i <= amount; i ) { for (int j = 0; j < coins.length; j ) { if (i >= coins[j]) { dp[i] = Integer.min(dp[i], dp[i - coins[j]] 1); } } } return dp[amount] == amount 1 ? -1 : dp[amount]; } ``` #求职# #面试# #实习#
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP