JAVA 复习题
简单题
1. 计算机网络传输层有哪些协议?分别适用于什么场景?
传输层核心协议:TCP、UDP
- TCP:面向连接、可靠传输。适用:文件传输、网页访问、数据库连接(需要数据不丢失、顺序正确)。
- UDP:无连接、不可靠,开销小。适用:直播、视频通话、DNS查询、游戏(允许少量丢包,优先速度)。
2. 多线程的使用场景有哪些?线程开启多少个合适?判断标准有哪些?
场景:IO密集型(文件读写、网络请求)、后台异步任务、并行计算。
线程数量:
- CPU密集型:核心数+1;
- IO密集型:2*CPU核心数。 判断标准:看CPU利用率、IO等待时间,减少线程上下文切换,避免过多线程抢占资源。
3. 线程池的提交方式有哪几种?
4. 锁的实现原理介绍一下?
以synchronized为例:对象头包含Mark Word,存放锁标记。 无锁→偏向锁→轻量级锁(CAS自旋)→重量级锁(OS互斥锁)。 底层:CAS + 对象头MarkWord + 操作系统互斥原语。通过竞争锁,保证同一时间只有一个线程执行临界区代码,保证原子性。
5. TCP协议中拥塞控制的主要作用是什么?
防止发送方发送数据太快,造成网络拥堵、报文大量丢失。动态调整拥塞窗口大小,控制发送速率,避免网络过载。四个阶段:慢启动、拥塞避免、快重传、快恢复。
6. String类的常用函数有哪些?列举十种。
length()、charAt()、substring()、indexOf()、lastIndexOf()、equals()、equalsIgnoreCase()、trim()、split()、replace()、toUpperCase()、toLowerCase()
7. String和StringBuffer,StringBuilder的区别有哪些?所有类名包含Buffer的类的内部实现原理是什么?有什么优势?

- 操作少量的数据 = String
- 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
- 多线程操作字符串缓冲区下操作大量数据 = StringBuffer
- Buffer类底层:可变字符数组,预分配容量,扩容时新建数组复制内容。优势:字符串拼接不会频繁创建新对象,减少GC压力。
8. String字符串的不可变是指哪里不可变?
底层存储字符的value数组被final修饰,数组引用不能指向新数组;数组内元素一旦初始化,不能修改。String引用变量可以重新赋值,不是变量不可变。
9. HTTP协议有哪些字段,列举3个就可以。
请求头:Host、User-Agent、Content-Type、Cookie、Accept。
10. Java异常类有哪些?分别管理什么异常?
Throwable分两大分支:
- 受检异常(编译期):IOException、SQLException
- 非受检异常(运行时RuntimeException):NullPointerException、ArrayIndexOutOfBounds
11. Java反射获取类信息的方式有哪几种?分别是什么?
12. Java代理的主要方法有哪几种?列举代理的使用场景2个。
静态代理、JDK动态代理、CGLIB动态代理。
场景:AOP切面、事务控制、日志记录。
13. equals()方法的作用是什么?重写equals需要注意哪些事项?为什么?
- 基本数据类型:比较数值(值)
- 引用数据类型:永远比较对象内存地址
- Object 原生未重写:底层就是return this == obj,比较内存地址。
- String、Integer 等包装类:重写 equals 方法,比较对象内容(值)。
重写要求:
14. Java是按值传递还是按引用传递?什么是引用传递,什么是值传递,哪些语言支持引用传递?
Java只有值传递。 值传递:传递的是副本,方法内修改副本不影响原变量。
引用传递:传递变量本身的地址,方法内修改会直接修改原始变量。
C++、C#支持引用传递。
Java传递引用类型时,传递的是引用地址副本,仍然属于值传递。
15. 描述java的类初始化顺序?如果存在继承,初始化顺序会如何
无继承:静态变量/静态代码块 → 成员变量/构造代码块 → 构造方法。
有继承:父类静态 → 子类静态 → 父类成员、构造块 → 父类构造 → 子类成员、构造块 → 子类构造。
静态只加载一次。
16. 本地方法栈有什么作用?
为native本地方法(C/C++写的方法)服务,存放native方法的局部变量、返回地址。JVM调用操作系统底层方法时使用。
17. 描述Java的双亲委派机制,为什么要用到双亲委派机制
Java双亲委派机制是指在类加载过程中,类加载器会按照一定的顺序委派给父类加载器来尝试加载类。这个机制可以确保类的加载安全和防止类的重复加载。下面是一个简要解答核心知识的表格:

通过Java双亲委派机制,可以实现类加载的安全性和避免重复加载,同时也允许开发者自定义ClassLoader来实现特定需求的类加载行为。
18. 重写和重载的区别是什么?
19. 子类构造方法调用父类构造方法的注意事项有哪些?
20. 子类实例初始化是否触发发父类实例初始化?
会。 创建子类对象,一定会先初始化父类实例。
21. instanceof关键字的作用是什么?
判断对象是不是某个类(或子类)的实例。obj instanceof User,返回布尔值。
22. 基本类型的强制类型转换是否会丢失精度?引用类型的强制类型转换需要注意什么?
基本类型:大范围转小范围,会丢失精度(double→int,long→short)。
引用类型强制转换:只能向上转型(自动);向下强转必须保证对象实际类型是目标类/子类,否则抛出ClassCastException。建议配合instanceof判断。
23. 重入锁有哪些?为什么要有重入锁?
synchronized、ReentrantLock。
作用:同一个线程拿到锁之后,再次进入同步代码块,可以再次获取锁,不会自己死锁。
24. 指令重排序的优点是什么?由什么原因导致的?
优点:CPU优化,调整指令执行顺序,充分利用CPU流水线,提升执行性能。
原因:JVM编译器、CPU处理器为了性能做的优化。 volatile可以禁止指令重排。
25. Arrays.sort()的内部原理介绍一下?
JDK8:
- 基本类型:双轴快速排序(DualPivotQuicksort)
- 引用类型:TimSort(归并+插入排序),稳定排序。
26. 堆排序的时间复杂度是多少,空间复杂度是多少?
时间复杂度:O(nlogn),最好最坏平均都是O(nlogn) 空间复杂度:O(1),原地排序。
27. 字符串“asdasjkfkasgfgshaahsfaf”经过哈夫曼编码之后存储比特数是多少?
字符统计:a:6,s:5,f:4,k:2,g:2,h:2,d:1,j:1
哈夫曼树构建: 总比特= 61 + 52 +42 +23 +23 +23 +14 +14 = 46 bit。
28. CPU高速缓存的优点和缺点有哪些?
优点:速度极快,减少访问内存耗时,提升CPU吞吐。
缺点:容量小;存在缓存一致性问题;多核心下缓存同步开销。
29. 线程安全的类有哪些?列举2个以上就可以
Vector、HashTable、StringBuffer、ConcurrentHashMap
30. 什么是LRU算法?
最近最少使用。缓存满时,淘汰最长时间没有被访问的数据。
核心思想:保留热点数据,淘汰冷数据。
31. TCP协议有哪些协议字段?如何保障可靠传输的?滑动窗口解决了什么问题?
字段:序号、确认号、标志位、窗口大小。
可靠传输:序列号+ACK确认、超时重传、校验和。
滑动窗口:流量控制,接收方告诉发送方最多能接收多少数据,防止发送方发太快淹没接收缓冲区。
32. 什么是三次握手,什么是四次挥手。
三次握手:建立TCP连接。
四次挥手:断开TCP连接。
1.客户端FIN;2.服务端ACK;3.服务端FIN;4.客户端ACK。
33. 什么是深拷贝?什么是浅拷贝?
浅拷贝:拷贝对象,引用成员变量只复制地址,新旧对象共用子对象。
深拷贝:拷贝整个对象,所有嵌套对象全部新建独立副本,修改互不影响。
34. 访问器如何保障线程安全?举例说明。
get/set访问方法加synchronized锁,保证同一时刻只有一个线程读写变量。
private int num;
public synchronized void setNum(int v){num=v;}
public synchronized int getNum(){return num;}
35. 抽象类和接口的不同点和相同点有哪些?

- 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
36. final关键字能否防止指令重排序?能否代替volatile?
final可以禁止构造对象内的指令重排,保证对象安全发布;但是不能代替volatile。volatile保证可见性+禁止读写重排,final不保证变量可见性。
37. static修饰的模块什么时候开始初始化?
类加载的初始化阶段。第一次主动使用类的时候触发(new、静态方法/静态变量访问、反射等)。
38. 什么是对象锁,什么是类锁?
对象锁:锁绑定实例对象,synchronized修饰普通方法、锁对象。多个实例互不干扰。
类锁:锁绑定Class对象,synchronized静态方法、锁类.class。全局一把锁。
39. 进程和线程的区别是什么?进程间的通信方式有哪些?线程间的通信方式有哪些?
进程:资源分配最小单位,独立内存空间;
线程:CPU调度最小单位,共享进程内存。
进程通信:管道、socket、消息队列、共享内存、信号量。 线程通信:wait/notify、共享变量、Lock、CountDownLatch。
40. 类锁和对象锁是否是互斥的?
不互斥。类锁锁的是Class对象;对象锁锁实例对象。两个锁对象不一样,可以同时执行。
41. 什么是注解,注解可以作用类的哪些部分?
注解是元数据,给程序附加说明信息,不直接执行。
可作用:类、接口、方法、成员变量、参数、局部变量。
42. 内部类有哪几种?分别适用于那些场景?
4种:成员内部类、静态内部类、局部内部类、匿名内部类。
- 成员内部类:访问外部类成员;
- 静态内部类:不需要外部实例,工具类;
- 局部内部类:方法内临时使用;
- 匿名内部类:快速实现接口/抽象类(回调、线程)。
43. finally的作用,一般用于什么场景?
finally代码块一定执行(除JVM退出),用于资源释放:关闭流、数据库连接。
44. 什么是栈溢出?什么是堆溢出?什么是堆外内存?
栈溢出StackOverflowError:方法调用深度过大,栈帧超过栈容量(递归太深)。
堆溢出OOM:堆内存不足以创建新对象。
堆外内存:不在JVM堆内,操作系统直接分配的内存,NIO的DirectBuffer。
45. Java的集合类有哪些?
Collection:List(ArrayList、LinkedList、Vector);Set(HashSet、TreeSet) Map:HashMap、TreeMap、HashTable、ConcurrentHashMap
46. 什么是泛型,请写一个泛型队列或者泛型栈。
泛型:参数化类型,编译期类型检查,避免类型强转。 泛型栈示例:
class Stack<T>{
private Object[] arr = new Object[10];
private int index = 0;
public void push(T t){arr[index++]=t;}
public T pop(){return (T)arr[–index];}
}
47. 反射能否获取私有信息,如果能,需要注意什么?
可以。setAccessible(true)开启访问权限。
注意:会破坏封装;有安全管理器限制;性能略低。
48. 线程的状态有哪些?
NEW新建、RUNNABLE可运行、BLOCKED阻塞、WAITING等待、TIMED_WAITING计时等待、TERMINATED终止。
49. 线程.start()是进入什么状态?
调用start(),线程进入RUNNABLE(可运行),等待CPU调度,不是直接运行。
50. 等待队列和阻塞队列的区别是什么?
等待队列:synchronized的监视器等待集合,wait进入,notify唤醒。 阻塞队列(BlockingQueue):并发容器,take()/put()自带阻塞,生产者消费者模型,底层封装锁+等待队列。
51. sleep()和wait()的区别是什么?
52. sleep(1)什么作用,都用于哪些场景?
作用:让出CPU,进入TIMED_WAITING,至少暂停1ms。 场景:简单限流、让出CPU给其他线程、简单轮询降频。
53. 什么是中断机制?举一个中断响应的例子。
中断是线程的标记,不是直接终止线程。interrupt()设置中断标记,线程检测标记自行停止。
while(!Thread.currentThread().isInterrupted()){
//业务
}
54. 守护线程是什么?什么是协程?
守护线程:后台服务线程,用户线程全部结束,守护线程自动退出(GC线程)。
协程:用户态轻量级线程,由程序调度,占用资源远小于线程。
55. 形成死锁的条件是什么?如何避免死锁?
4条件:互斥、持有并等待、不可剥夺、循环等待。
避免:统一锁获取顺序、设置超时、破坏持有等待。
56. 基本类型的数据存在jvm的哪个区域?
局部变量里的基本类型:虚拟机栈;作为对象成员变量的基本类型,在堆。
57. 多线程的使用场景有哪些?
IO密集型任务:网络请求、文件读写;后台异步任务;并行计算;消息消费。
58. Throw和Throws的区别?
throws写在方法声明,声明本方法可能抛出异常;
throw写在方法体内,手动抛出一个异常实例。
59. Object类的方法有哪些?分别有什么作用?
60. 总线锁的优缺点是什么?
总线锁:CPU锁住总线,同一时刻只有一个CPU访问内存。
优点:简单,保证原子性;
缺点:锁整个总线,多核CPU并发性能差。后来优化为缓存锁(MESI)。
代码题(每题10分)
1. 写三个线程t1、t2、t3,t1输出A,t2输出B,t3输出C,循环输出 ABABC
思路:用锁+状态标记,控制线程轮流执行,循环顺序 A → B → A → B → C
public class ABCThread {
static Object lock = new Object();
//state:0输出A,1输出B,2输出A,3输出B,4输出C,循环
static int state = 0;
public static void main(String[] args) {
Thread t1 = new Thread(()->{
while(true){
synchronized (lock){
while(state !=0 && state !=2){
try {lock.wait();} catch (InterruptedException e) {}
}
System.out.print("A");
state++;
lock.notifyAll();
}
}
},"t1");
Thread t2 = new Thread(()->{
while(true){
synchronized (lock){
while(state !=1 && state !=3){
try {lock.wait();} catch (InterruptedException e) {}
}
System.out.print("B");
state++;
if(state==5) state=0;
lock.notifyAll();
}
}
},"t2");
Thread t3 = new Thread(()->{
while(true){
synchronized (lock){
while(state !=4){
try {lock.wait();} catch (InterruptedException e) {}
}
System.out.print("C");
state++;
if(state==5) state=0;
lock.notifyAll();
}
}
},"t3");
t1.start();
t2.start();
t3.start();
}
}
逻辑:state 0(A)→1(B)→2(A)→3(B)→4(C),state重置为0,循环ABABC。
2. 默写懒汉式单例模式,以及代码解释
public class Singleton {
//私有静态变量,不初始化
private static Singleton instance;
//私有构造,禁止外部new
private Singleton(){}
//获取实例,第一次调用才创建
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
解释:懒汉式,延迟加载,调用getInstance才创建对象。缺点:多线程环境线程不安全,多线程同时进入if会创建多个实例。 【可选:线程安全版本】加synchronized:
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
推理题(10分,不少于500字)
1.Tomcat如何访问到Controller的,内部实现原理是什么?
浏览器输入地址发起HTTP请求,请求经过网络到达Tomcat,整体流程分为:端口接收、解析请求、匹配Servlet、转发到SpringMVC的Controller。
Tomcat底层是Socket通信,启动时在8080端口开启ServerSocket,持续监听客户端连接。浏览器发送HTTP请求报文,操作系统内核把TCP数据包交给Tomcat。Tomcat的Connector组件负责接收Socket连接,读取HTTP报文,解析请求行、请求头,封装成HttpServletRequest对象;同时准备HttpServletResponse对象,用来回写响应数据。
Connector解析完成后,把请求交给Container容器。Container包含Engine、Host、Context、Wrapper四层容器。Engine代表整个引擎,Host对应虚拟主机,Context对应一个web项目,Wrapper封装Servlet。Tomcat根据请求url,匹配对应的Context项目。
SpringMVC项目中,web.xml自动注册DispatcherServlet,它是前端控制器,本质是一个Servlet。当请求进入Context后,匹配到DispatcherServlet,进入它的service方法。DispatcherServlet是整个MVC的入口。DispatcherServlet内部调用doDispatch核心方法。
doDispatch内部流程:首先通过HandlerMapping,根据请求URL查找对应的Controller处理器。HandlerMapping保存URL和Controller方法的映射关系,扫描项目所有@Controller注解,把@RequestMapping地址和方法绑定。找到Handler之后,获取对应的HandlerAdapter,HandlerAdapter负责调用Controller方法。
HandlerAdapter通过反射执行Controller里的目标方法,传入请求参数。Controller执行业务逻辑,返回ModelAndView或者直接返回JSON。 如果返回视图,DispatcherServlet调用ViewResolver视图解析器,找到页面,渲染数据;如果是@ResponseBody,直接把返回对象转为JSON,写入Response。
处理完成后,DispatcherServlet把结果写入HttpServletResponse。Tomcat的Connector拿到response,组装HTTP响应报文,通过Socket写回浏览器。请求链路结束,关闭连接(HTTP1.1长连接则复用连接)。
总结:Tomcat负责底层网络通信、HTTP报文解析,把请求交给Servlet;SpringMVC的DispatcherServlet作为核心Servlet,完成URL路由,调用Controller,处理返回结果。Tomcat提供Web运行环境,SpringMVC在Servlet之上做路由和业务分发,二者配合完成从浏览器访问到Controller执行的完整流程。
网硕互联帮助中心



评论前必须登录!
注册