Java测试题(上)
1. 传输层协议及使用场景
TCP:面向连接、可靠传输、保证数据顺序与完整性,适用于对数据准确性要求高的场景,如文件传输、Web请求(HTTP/HTTPS)。
UDP:无连接、低延迟、不保证顺序与可靠性,适用于实时性要求高、可容忍少量丢包的场景,如实时音视频、DNS查询、游戏数据同步。
2. 多线程使用场景与线程数估算
使用场景:
高并发请求处理
定时任务与异步任务处理
计算密集型任务的并行计算
IO密集型任务的重叠执行
生产者-消费者模型
线程数估算:
CPU密集型任务:
线程数 = CPU核心数 + 1
IO密集型任务:
线程数 = CPU核心数 × (1 + 平均IO等待时间 / CPU计算时间)
判断标准:
CPU利用率低于50%时,可适当增加线程数
CPU利用率高于90%时,应减少线程数或优化代码
任务队列持续积压导致延迟上升时,需扩容线程池
线程数不得超过操作系统限制(如Linux默认每进程1024线程)
3. 线程池的提交方式
方法 | 返回值 | 说明 |
---|---|---|
execute(Runnable command) | void | 提交Runnable任务,无返回值 |
submit(Callable<T> task) | Future<T> | 提交Callable任务,返回Future对象 |
submit(Runnable task) | Future<?> | 提交Runnable任务,返回Future对象 |
submit(Runnable task, T result) | Future<T> | 提交Runnable任务并指定返回结果 |
4. 锁的实现原理
硬件层面:通过CPU原子指令(如CAS、LL/SC)保证操作的原子性。
操作系统层面:利用互斥量(mutex)或自旋锁(spinlock)实现线程的阻塞与唤醒。
JVM层面:
synchronized基于对象头的Mark Word和Monitor实现
ReentrantLock基于AQS(AbstractQueuedSynchronizer)队列管理线程竞争
锁升级机制:偏向锁 → 轻量级锁 → 重量级锁,逐级升级以优化性能
优化策略:锁消除、锁粗化、读写分离
分布式锁:Redis、ZooKeeper实现跨进程锁,需解决一致性问题
5. TCP拥塞控制的主要作用
通过慢开始、拥塞避免、快重传、快恢复等算法,防止网络中数据量过大导致网络拥塞崩溃,动态调整发送窗口大小,保证网络稳定性与传输效率。
6. String常用函数(列举10个)
charAt(int index)
contains(CharSequence s)
endsWith(String suffix)
equals(String another)
length()
replace(char oldChar, char newChar)
substring(int beginIndex, int endIndex)
split(String regex)
valueOf(int i)
concat(String str)
7. String、StringBuffer与StringBuilder的区别
特性 | String | StringBuffer | StringBuilder |
---|---|---|---|
可变性 | 不可变 | 可变 | 可变 |
线程安全 | 安全(不可变天然安全) | 安全(方法同步) | 不安全 |
使用场景 | 字符串常量、作为Map的key | 多线程环境下字符串拼接 | 单线程环境下字符串拼接 |
内部实现原理:三者底层均为
char[]
,StringBuffer与StringBuilder在容量不足时进行动态扩容(默认扩容为原容量的2倍+2)。优势:StringBuffer与StringBuilder通过动态扩容减少频繁创建新对象的开销,提高效率。
8. String字符串的不可变具体指什么?
内容不可变:字符串对象创建后,其内容(字符数组)不可修改。
内存地址不可变:字符串对象在内存中的地址不可变,任何修改操作都会创建新的字符串对象。
9. HTTP协议常见字段(列举3个)
Content-Type
:指定请求或响应的媒体类型,告诉服务器或客户端如何解析数据。User-Agent
:标识客户端软件信息,服务器可根据此字段返回适配内容。Cookie
:由服务器设置,客户端后续请求自动携带,用于维持会话状态。
10. Java异常体系
受检异常(Checked Exception):编译器强制要求处理,如
IOException
、SQLException
。非受检异常(Unchecked Exception):运行时异常,编译器不强制处理,如
NullPointerException
、ArrayIndexOutOfBoundsException
。错误(Error):严重系统级问题,程序通常无法恢复,如
OutOfMemoryError
、StackOverflowError
。
11. Java反射获取类信息的三种方式
Class.forName("全限定类名")
类名.class
对象.getClass()
12. Java代理方式及使用场景
静态代理:代理类在编译期确定,手动编写代理类。
动态代理:运行时动态生成代理类,如JDK动态代理、CGLIB代理。
使用场景:
AOP(面向切面编程):日志、事务、权限控制
RPC(远程过程调用):客户端代理远程服务接口
13. equals()方法的作用及重写注意事项
作用:默认实现比较两个对象的引用是否指向同一内存地址,重写后通常用于比较对象的内容是否相等。
重写注意事项:
必须同时重写
hashCode()
方法,保证相等的对象具有相同的哈希码满足自反性、对称性、传递性、一致性
重写后需确保
equals()
与hashCode()
逻辑一致,避免在哈希集合中出现逻辑错误
14. Java参数传递方式
Java采用值传递:
基本类型:传递值的副本,修改副本不影响原值
引用类型:传递引用的副本(指向对象的地址),修改副本指向的对象内容会影响原对象,但修改副本本身(指向新对象)不影响原引用
引用传递:方法调用时传递的是变量的原始引用(别名),修改参数直接影响原变量(Java不支持)
支持引用传递的语言:C++(通过引用符号
&
)、C#(通过ref
/out
关键字)
15. Java类初始化顺序(含继承)
单个类初始化顺序:
静态变量和静态代码块(按书写顺序)
实例变量和实例代码块(按书写顺序)
构造器
存在继承时的初始化顺序:
父类静态变量和静态代码块
子类静态变量和静态代码块
父类实例变量和实例代码块
父类构造器
子类实例变量和实例代码块
子类构造器
16. 本地方法栈的作用
用于支持native方法的执行,保存native方法的局部变量、参数、返回值,并管理native方法的调用过程。
17. Java双亲委派机制
机制描述:
类加载器收到加载请求时,先不自行加载,而是委托给父加载器
父加载器检查是否已加载该类,若已加载则直接返回
若未加载,继续向上委托,直到顶层启动类加载器
若顶层加载器无法加载,子加载器才尝试自行加载
目的:避免类的重复加载,保证核心类库的安全性(防止核心类被篡改)
18. 重写与重载的区别
表格
复制
区别维度 | 重写(Override) | 重载(Overload) |
---|---|---|
发生范围 | 子类与父类之间 | 同一个类内部 |
方法签名 | 方法名、参数列表相同 | 方法名相同,参数列表不同 |
返回类型 | 可协变 | 可不同 |
访问权限 | 不能严于父类 | 无限制 |
19. 子类构造方法调用父类构造方法的注意事项
子类构造方法中调用父类构造方法时,必须位于第一行,使用
super()
或super(参数)
显式调用若未显式调用,编译器默认调用父类无参构造器;若父类没有无参构造器,编译报错
20. 子类实例初始化是否会触发父类实例初始化?
会。子类实例化前,必须先完成父类的实例初始化(包括实例变量、实例代码块、构造器)。
21. instanceof关键字的作用
用于判断对象是否为指定类或其子类的实例,或是否实现了指定接口,返回boolean值。
22. 强制类型转换注意事项
基本类型强制转换:
大范围类型转小范围类型(如double转int)可能丢失精度或溢出
引用类型强制转换:
只能将父类引用转换为子类引用(向下转型),且实际对象必须是子类实例,否则抛出
ClassCastException
转换前建议使用
instanceof
进行类型检查
23. Java中的重入锁
常见重入锁:
synchronized
关键字(隐式重入锁)ReentrantLock
类(显式重入锁)
重入锁的意义:允许同一个线程多次获取同一把锁,避免嵌套同步代码块时发生死锁,提高代码灵活性和可读性
24. 指令重排序的优点与原因
优点:
提高CPU指令并行度
隐藏内存访问延迟
优化缓存利用率
原因:
编译器优化(指令重排)
CPU乱序执行(流水线技术)
内存层级缓存延迟
25. Arrays.sort()内部原理
基本类型数组:使用双轴快速排序(Dual-Pivot Quicksort)
对象类型数组:使用TimSort(归并排序与插入排序的混合优化算法,稳定排序)
26. 堆排序复杂度
时间复杂度:O(n log n)
空间复杂度:O(1)(原地排序)
27. 字符串“asdasjkfkasgfgshaahsfaf”哈夫曼编码后的比特数
经过哈夫曼编码后,该字符串存储所需比特数为 56位。
28. CPU高速缓存的优缺点
优点:
访问延迟低(纳秒级)
提高并发性能
减少CPU空闲等待
降低内存带宽压力
缺点:
容量有限
缓存一致性协议(如MESI)可能引入延迟
缓存未命中时性能下降明显
29. Java线程安全类举例
StringBuffer
:线程安全的可变字符串ConcurrentHashMap
:线程安全的哈希表Vector
:线程安全的动态数组(已过时,推荐使用ArrayList
+同步包装类)
30. LRU算法描述
Least Recently Used(最近最少使用)缓存淘汰策略:
新访问的数据移动到缓存头部
重复访问的数据也移动到头部
缓存满时淘汰尾部最久未使用的数据
30. Spring Bean 容器 vs. Spring IoC 容器
Q:二者到底有什么区别?
维度 | Spring Bean 容器 | Spring IoC 容器 |
---|---|---|
本质 | 运行时实体,真正干活的容器 | 设计思想,一种理念 |
职责 | 负责 Bean 的创建、依赖注入、生命周期管理(初始化、销毁、作用域等) | 定义“谁控制谁”——由框架而非程序员控制对象创建与依赖 |
举例 | ApplicationContext 、BeanFactory 的具体实现类 | “控制反转”思想本身 |
关系 | 是 IoC 思想的具体实现 | 是 Bean 容器背后的指导思想 |
IoC 通过反转控制权,降低组件之间的耦合度,提高可维护性与可测试性。
31. 如何理解 Spring IoC(控制反转)?
一句话定义
把“对象创建、依赖查找、生命周期管理”的掌控权从业务代码 反转 给 Spring 框架,开发者只关心业务逻辑,不关心对象如何实例化、如何装配。
三个关键点
谁控制谁:框架控制应用程序所需对象的生命周期。
为何反转:传统方式由程序主动
new
对象,IoC 改为由容器被动注入(DI)。带来的好处:
降低耦合:业务类只依赖接口而非实现
提高可测试性:便于 Mock 与单元测试
统一配置:通过 XML、注解或 JavaConfig 集中管理