Java面试
2024-02-20 18:00:51 1 举报
AI智能生成
Java面试宝典
作者其他创作
大纲/内容
Java反射
反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;
并且对于任意一个对象,都能够调用它的任意一个方法;
并且对于任意一个对象,都能够调用它的任意一个方法;
反射使用步骤
1 获取想要操作类的Class对象
2 调用Class类中的方法
3 使用反射API操作这些信息
Spring框架
谈谈Spring框架
spring 是一个开源的轻量级 JavaBean 容器框架,降低了应用开发的复杂性
有ioc控制反转,依赖注入松耦合
AOP面向切面
方便集成
什么是IOC
IOC是一种设计思想,从下层控制上层反转到→上层控制下层;通过依赖注入实现
把创建和查找依赖对象的控制权交给 IoC 容器,由 IoC 容器进行注入、组合对象。这样对象与对象之间是松耦合、便于测试、功能可复用
什么是AOP
AOP是一种面向切面,切开对象的封装,把影响类的公共行为封装到一个可重用的模块中,组成一个切面,代码复用,降低耦合
实现AOP
动态代理
静态织入
注解
bean的注册
@Component //注册所有bean
@Controller //注册控制层的bean
@Service //注册服务层的bean
@Repository //注册dao层的bean
@Controller //注册控制层的bean
@Service //注册服务层的bean
@Repository //注册dao层的bean
bean的注入
@Autowired 作用于 构造方法、字段、方法,常用于成员变量字段之上。
@Autowired + @Qualifier 注入,指定 bean 的名称
@Resource JDK 自带注解注入,可以指定 bean 的名称和类型等
@Autowired + @Qualifier 注入,指定 bean 的名称
@Resource JDK 自带注解注入,可以指定 bean 的名称和类型等
spring中的bean是线程安全的吗?
Spring不保证bean的线程安全
默认 spring 容器中的 bean 是单例的。当单例中存在竞态条件,即有线程安全问题
bean的作用域?
singleton
prototype
request
session
application
SpringMvc的运行流程
@RequestMapping的作用是什么?
@RequestMapping 是一个注解,用来标识 http 请求地址与 Controller 类的方法之间的映射。
@Autowired的作用是什么?
它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。
什么是spring boot?为什么要用?
spring boot 基于 spring 框架的快速开发整合包。内置了tomcat服务器,直接可以打包成jar包就能独立运行
优点:
编码
配置
部署变得简单
编码
配置
部署变得简单
MySQL
数据库三范式
第一范式:列不可再分
第二范式:行可以区分,主键约束
第三范式:表的非主属性不能依赖其他的非主属性,外键约束
mysql常用引擎包括:MYISAM、Innodb、Memory、MERGE
说说InnoDB与MyISAM的区别
MyISAM不支持事务,InnoDB支持事务
MyISAM支持的场景:
频繁执行全表count
对数据库增删改频率不高、频繁进行查询操作
没有事务
InnoDB支持的场景
数据增删改频繁的操作
可靠性要求比较高、支持事务
数据库锁的分类
数据库事务的四大特性(ACID)
原子性
一致性
隔离性
持久性
事务隔离级别下的并发问题
脏读、幻读、不可重复读
脏读:A在读取一行数据后,B对这一行数据进行了更新,并回滚操作,导致A读取的数据时脏数据
幻读:A在对多行数据读取时,此时B更新了一些数据,导致A发现了一些原本不存在的数据,就像发生幻觉一样
不可重复读:A在重复读取一行数据时,B更新了这一行数据,导致A读取的数据前后不一致
左连接、右连接、内连接和全外连接的区别
左连接(left join):返回包括左表中的所有记录和右表中连接字段相等的记录。
右连接(right join):返回包括右表中的所有记录和左表中连接字段相等的记录。
内连接(inner join):只返回两个表中连接字段相等的记录。
全外连接(full join):返回左右表中连接字段相等的记录和剩余所有记录。
右连接(right join):返回包括右表中的所有记录和左表中连接字段相等的记录。
内连接(inner join):只返回两个表中连接字段相等的记录。
全外连接(full join):返回左右表中连接字段相等的记录和剩余所有记录。
Redis
介绍一下Redis
Redis是一个开源的保存键值对、基于内存、支持多种数据结构的存储系统,可以作为数据库、缓存。
Redis支持哪些数据类型?
支持五种数据类型
hash
string
list
set
sorted set
Redis有哪些优缺点?
1 性能极高,能到10万次/s的读写速度
2 支持数据的持久化,对数据的更新采用Copy-on-write技术,可以异步地保存到磁盘上
3 支持丰富的数据类型
4 支持数据的备份,快速的主从复制
Redis使用单线程模型为什么性能依然很好?
1 基于内存的,数据读写快
2 避免线程切换浪费资源
3 基于非阻塞IO,多路复用
4 使用了高性能数据结构,如 Hash
Redis各数据类型最大容量是多少?
Strings:一个 String 类型的 value 最大可以存储512M
Lists:元素个数最多为 2^32-1 个,即 4294967295 个
Sets:元素个数最多为 2^32-1 个,即 4294967295 个
Hashes:键值对个数最多为 2^32-1 个,即 4294967295 个
Sorted sets类型:同 Sets
Lists:元素个数最多为 2^32-1 个,即 4294967295 个
Sets:元素个数最多为 2^32-1 个,即 4294967295 个
Hashes:键值对个数最多为 2^32-1 个,即 4294967295 个
Sorted sets类型:同 Sets
Redis持久化机制有哪些
RDB
数据集快照的方式半持久化模式,记录 redis 数据库的所有键值对
AOF
指所有的命令行记录以 redis 命令请求协议的格式完全持久化存储,保存为 aof 文件
Redis过期键的删除策略有哪些?
定时删除
设置键过期时间是,同时设置一个定时器,到了过期时间就进行删除操作
惰性删除
不主动删除过期键,只有访问到键时,检查是否过期并进行删除
Redis有哪些适用场景?
会话缓存
全页缓存等
Redis的缓存雪崩,缓存击穿、缓存穿透
缓存雪崩:缓存同一时间大面积失效,大量的访问到数据库而崩掉
解决策略:加锁
缓存击穿:一个热点key突然失效,导致大量请求访问到数据库
解决:不设置这个key的过期时间
缓存穿透:缓存、数据库中没有这个key,导致在缓存找不到又去数据库查询,并返回空
解决:设置布隆过滤器
MQ
MQ是什么?为什么使用?
MQ(Message Queue)消息队列,是 "先进先出" 的一种数据结构。
MQ 的作用:一般用来解决应用解耦,异步处理,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性架构。
MyBatis
介绍一下MyBatis
MyBatis是一款持久层框架
:支持自定义 SQL、存储过程以及高级映射
免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
通过简单的 XML 或注解来配置和映射
:支持自定义 SQL、存储过程以及高级映射
免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
通过简单的 XML 或注解来配置和映射
#{} 和 ${} 的区别
MyBatis 在处理 #{} 时,会将 SQL 中的 #{} 替换为 ?
使用 #{} 可以有效地防止 SQL 注入。
MyBatis 在处理 ${} 时,会直接把 ${} 替换为参数值,存在 SQL 注入的风险
mybatis的一级缓存二级缓存
一级缓存是SqlSession级别的缓存,默认开启的
二级缓存是NameSpace级别发缓存,多个sqlsession共享的,使用时需要在mapper.xml文件里用cache标签开启
访问顺序是:二级缓存→一级缓存→数据库
安全
如何避免sql注入?
1 设置数据库操作权限
2 使用正则判断
3 对特殊字符进行转义处理
JVM相关面试题
JVM虚拟机结构
由虚拟机栈
堆
方法区
本地方法栈
JVM判断如何对象是否存活?
引用计数法:设置一个计数器,一个对象被引用就加一,取消引用就减一,当引用数为零时则该对象没有存活;
但是会出现循环引用,A引用B,B引用A且两者引用都不为零,导致无法判断是否存活;
但是会出现循环引用,A引用B,B引用A且两者引用都不为零,导致无法判断是否存活;
可达性分析
用GC roots 到某一对象的路径,若可达就存活;
GC分代收集
在新生代-复制算法
在老年代-标记整理算法
Java中的四种引用
强引用:在程序内存不足(OOM)的时候也不会被回收
软引用:在程序内存不足时会被回收;需要SoftReference类来实现
弱引用:比软引用更弱,垃圾回收机制一运行就被回收;需要使用Weak Reference类来实现
虚引用:主要作用是跟踪对象被垃圾回收的状态
Java I/O
阻塞IO模型
在读写数据中会发生阻塞现象,若数据处于未就绪状态,用户线程继续处于阻塞状态,用户线程交出CPU
非阻塞IO模型
用户线程不需要等待,马上就会得到一个结果,若得到error便知道数据未准备就绪;期间线程会不断询问内核数据是否准备就绪;
非阻塞IO不会交出CPU,而会一直占用CPU
非阻塞IO不会交出CPU,而会一直占用CPU
多路复用 IO 模型
信号驱动 IO 模型
异步 IO 模型
JAVA NIO
NIIO三大核心部分:
传统 IO 基于字节流和字符流进行操作,而 NIO 基于 Channel 和 Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区
中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件
传统 IO 基于字节流和字符流进行操作,而 NIO 基于 Channel 和 Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区
中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件
1 Channel通道
2 Buffer(缓冲)
3 Selector
JVM 类加载机制
五个部分:加载,验证,准备,解析,初始化
加载.class文件、验证文件中的字节流是否符合虚拟机要求、准备变量要用的内存空间、解析并初始化;
Java集合
collection
list集合
ArrayList
有序可重复
底层使用数组
查询快,增删慢
线程不安全
Vcetor
排列有序可重复
使用数组(支持随机访问)
查询快增删慢
线程不安全,效率低
容量不够时,默认扩展一倍容量
LinkList
有序,可重复
底层使用链表
增删快,查找慢;add(),remove()方法快
set集合
HashSet
排列无序,不可重复
底层使用hash表实现
存取快
内部是hashmap
TreeSet
无序不可重复
底层二叉树实现
排序存储
内部是TreeMap和sortedSet
Map
HashMap
键不可重复、值可重复
底层hash表
线程不安全
HashMap 最多只允许一条记录的键为 null,允许多条记
录的值为 null
录的值为 null
底层是数组+链表+红黑树
当链表中的元素超过了 8 个以后,
会将链表转换为红黑树
会将链表转换为红黑树
负载因子默认:0.75;可以扩容,扩容后数组大小为当前的 2 倍
hashtable
键不可重复、值可重复
底层hash表
线程不安全
key,value都不为null
HashMap 和 Hashtable 的区别
1. 线程是否安全:
HashMap 是非线程安全的,HashTable 是线程安全的;
HashTable 内部的方法基本都经过synchronized 修饰。
HashTable 内部的方法基本都经过synchronized 修饰。
2.效率:
HashMap效率相对较高,因为HashTable加了锁,线程安全问题可以导致效率下降;
3. 对Null key 和Null value的支持
HashMap最多允许一条键值为null,可以有多条记录值为null;
Hash Table都不能为空
Hash Table都不能为空
4.初始大小和可扩容
HashTable默认为11,扩容为2n+1
HashMap默认16,扩容为原来2倍
5 底层数据结构
JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为
8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
HashSet 和 HashMap 区别
HashSet 底层就是基于 HashMap 实现的。
JAVA 多线程并发
4 种常见的创建线程的方式
一、重写 Thread 类的 run() 方法
2、继承 Thread 对象,重写 run() 方法
二、实现 Runnable 接口,重写 run() 方法。
三、实现 Callable 接口,使用 FutureTask 类创建线程
四、使用线程池创建、启动线程
有关线程池的题目
什么是线程池?
线程池是创建若干个线程放在一个容器内,需要时就放到线程池的任务队列里,用完再放回去,并不会被销毁
线程池的优点:
1 降低资源消耗:避免反复的创建线程,消耗资源
2 提高响应速度:当任务需要时直接就可以允许,不需要等到创建线程
3 提高线程的可管理性:使用线程池可以进行统一的分配,调优和监控
线程池的5种状态
1 running
2 shutdown
3 STOP
4 TIDYING
5 TERMINATED
线程生命周期
新建(New)、
就绪(Runnable):调用了start()方法
运行(Running):获得CPU,开始执行 run()方法
阻塞(Blocked)和:放弃CPU
死亡(Dead)5 种状态
就绪(Runnable):调用了start()方法
运行(Running):获得CPU,开始执行 run()方法
阻塞(Blocked)和:放弃CPU
死亡(Dead)5 种状态
Java锁
synchronized关键字
作用:
确保线程互斥地访问同步代码
保证共享变量的修改能够及时可见
有效解决重排序问题
确保线程互斥地访问同步代码
保证共享变量的修改能够及时可见
有效解决重排序问题
ReentrantLock 与 synchronized
1. ReentrantLock 通过方法 lock()与 unlock()来进行加锁与解锁操作,与 synchronized 会
被 JVM 自动解锁机制不同,ReentrantLock 加锁后需要手动进行解锁。为了避免程序出
现异常而无法正常解锁的情况,使用 ReentrantLock 必须在 finally 控制块中进行解锁操
作。
被 JVM 自动解锁机制不同,ReentrantLock 加锁后需要手动进行解锁。为了避免程序出
现异常而无法正常解锁的情况,使用 ReentrantLock 必须在 finally 控制块中进行解锁操
作。
2. ReentrantLock 相比 synchronized 的优势是可中断、公平锁、多个锁。这种情况下需要
使用 ReentrantLock。
使用 ReentrantLock。
乐观锁、悲观锁、自旋锁
乐观锁:即一种乐观的思想,认为读多写少,线程执行前没有问题,直到遇到并发写问题才加锁
悲观锁:悲观思想,事先认为读少写多,每次认为都有可能会出现并发写问题,在修改数据时都要加上锁
java中的悲观锁就是Synchronized
自旋锁:线程一直占用CPU自旋(等待)
公平锁与非公平锁
公平锁:分配机制是公平的,通常先对锁提出获取请求的线程会先被分配到锁
非公平锁:JVM 按随机、就近原则分配锁的机制则称为不公平锁
如何避免死锁
死锁发生的条件
互斥
占有且等待
破坏:一次性申请所有资源
不可抢占
破坏:可以主动释放资源
循环等待
破坏:按序申请资源
只需要破坏死锁条件的任意一个就可以避免死锁;互斥不可破坏!
其他三个条件,我们可以尝试
一次性申请所有的资源,破坏 "占有且等待" 条件
占有部分资源的线程进一步申请其他资源时,如果申请不到,主动释放它占有的资源,破坏 "不可抢占" 条件
按序申请资源,破坏 "循环等待" 条件
一次性申请所有的资源,破坏 "占有且等待" 条件
占有部分资源的线程进一步申请其他资源时,如果申请不到,主动释放它占有的资源,破坏 "不可抢占" 条件
按序申请资源,破坏 "循环等待" 条件
Java 中用到的线程调度
抢占式调度
抢占式调度指的是每条线程执行的时间、线程的切换都由系统控制
JVM线程调度
协同式调度
协同式调度指某一线程执行完后主动通知系统切换到另一线程上执行,这种模式就像接力赛一样
进程调度算法
优先调度算法
FCFS:先来先服务调度算法
SJF: 短作业优先调度算法
高响应比优先调度算法
时间片轮转法
系统将所有的就绪进程按先来先服务的原则排成一个队列,每次调度
时,把 CPU 分配给队首进程,并令其执行一个时间片。
时,把 CPU 分配给队首进程,并令其执行一个时间片。
0 条评论
下一页