Java后端开发 笔试知识点复习(四)
(一)Java基础
1.hashmap和hashtable
| 特性 | HashMap | Hashtable |
|---|---|---|
| 线程安全 | 否 | 是(方法用 synchronized) |
| 允许 null | 允许 key 和 value 为 null | 不允许 null |
| 继承 | AbstractMap | Dictionary(过时),并发环境推荐 ConcurrentHashMap |
| 初始容量 & 扩容 | 容量 16,扩容 2 倍 | 容量 11,扩容 2 倍 + 1 |
| 迭代器 | fail-fast | fail-fast(Enumeration 不是 fail-fast) |
2.内部类,抽象类,接口
-
内部类:定义在类内部的类。分为静态内部类、成员内部类、局部内部类、匿名内部类。
-
非静态内部类持有外部类的引用,可以访问外部类私有成员。
-
-
抽象类:用
abstract修饰,不能实例化,可以有构造方法和普通成员变量/方法。用于“is-a”关系。 -
接口:用
interface定义,Java 8 后可以有默认方法和静态方法。用于“can-do”关系。 -
区别:类可以多实现接口,但只能单继承抽象类。
3.static,final
-
static:属于类而非实例。
-
静态方法不能访问非静态成员。
-
静态代码块在类加载时执行一次。
-
-
final:修饰类(不可继承)、方法(不可重写)、变量(值不可变)。
-
引用变量被 final 修饰时,引用地址不可变,但对象内容可变。
-
4.异常 error,exception
-
Throwable子类:-
Error:系统级错误(如
OutOfMemoryError内存溢出,StackOverflowError),程序不应捕获。 -
Exception:程序应处理的异常。
-
受检异常(Checked):编译时检查,如
IOException、SQLException,必须 try-catch 或 throws。 -
非受检异常(Unchecked):
RuntimeException及其子类,如NullPointerException空指针,数组越界,可不用显式处理。
-
-
5.new Person("Test")与static{....}的执行顺序
-
当类首次被加载时,执行静态代码块(和静态变量赋值,按定义顺序)。
-
创建对象时,执行顺序:
-
父类静态代码块/静态变量(如果类未加载)
-
子类静态代码块/静态变量
-
父类实例变量/实例代码块
-
父类构造方法
-
子类实例变量/实例代码块
-
子类构造方法
-
-
所以:
static{}先于构造方法执行(且只执行一次)。
6.JRE,JDK,JVM
-
JVM:Java 虚拟机,执行字节码,提供内存管理、垃圾回收、即时编译等。
-
JRE:JVM + 核心类库(rt.jar 等),运行 Java 程序所需。
-
JDK:JRE + 开发工具(javac, jar, jdb 等),用于开发 Java 程序。
7.continue,break,return
-
continue:跳过本次循环剩余代码,进入下一次迭代(仅用于循环)。 -
break:跳出当前循环或 switch 语句。 -
return:结束当前方法,可返回值(void 方法中return;表示提前返回)。
8.byte,short,int
-
整数类型:
byte(8位, -128~127)、short(16位)、int(32位)。 -
运算时,byte/short 会自动提升为 int(防止溢出)。
-
字面量默认 int,赋值给 byte/short 需显式强制转换,除非值在范围内且编译器能推断。
9.派生类/子类/继承
(1)继承格式
-
Java 单继承,多实现,可以多重继承(A-->B-->C)
-
class SubClass extends SuperClass { ... }。
(2)子类可访问父类的哪些成员
-
public、protected:子类可直接访问。 -
默认(包访问权限):子类与父类在同一包中可访问。
-
private:不可直接访问,可通过父类的public/protected方法间接访问。
(3)子类构造器与super()
-
子类构造器第一行必须调用父类构造器(显式
super(...)或隐式super())。 -
如果父类没有无参构造器,子类必须显式
super(参数)。 -
常考错误:父类只有带参构造,子类未显式调用 → 编译错误。
(4)方法重写(Override)
派生类继承基类的非私有成员,可以重写虚方法(Java 中普通实例方法默认可重写,默认所有非静态、非私有、非 final 的实例方法都是虚方法。所有可被重写的方法)。
重写条件:方法名、参数列表相同,返回类型可以是父类返回类型的子类。子类声明抛出的异常不能更宽泛。
-
static 方法不能重写,只能隐藏(hide)。子类定义相同签名的 static 方法,调用时根据引用类型决定。
-
protected:子类可以重写,访问权限可以扩大(public)但不能缩小。
-
private方法不能重写,子类定义相同方法只是新方法,不是重写。
(5)成员变量与隐藏
-
子类可以定义与父类同名的成员变量(实例变量、静态变量),这叫隐藏。
-
访问时,通过引用类型决定(与静态方法类似)。
10.其他
-
main 函数:可以被其他方法调用(它是一个普通静态方法),程序启动由 JVM 调用 main,自己调用不会报错。
-
反射:可以访问私有成员,通过
setAccessible(true)。
(二)Web开发与框架
1.登录验证码怎么实现比较好
(1)登录时为什么要使用验证码?
-
防止暴力破解:避免攻击者通过自动化脚本无限尝试用户名/密码。
-
防止撞库攻击:即使密码已泄露,验证码增加一次额外校验。
-
防止机器注册/刷票:适用于注册、评论等场景。
-
区分人机:利用人类难以自动识别的任务(扭曲文字、图像识别)来阻挡简单脚本
(2)常见验证码
| 类型 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 图形验证码(字符扭曲) | 生成随机字符串,添加干扰线、噪点 | 实现简单,无需第三方 | 对残障用户不友好,OCR可破解 | 一般网站登录 |
| 短信/邮箱验证码 | 发送6位数字到手机/邮箱 | 用户操作简单,安全性较高 | 成本高,依赖通信渠道,可能被拦截 | 高安全操作(支付) |
| 滑动拼图/点选文字 | 拖动滑块完成拼图,或点击指定文字 | 用户体验好,难以自动化 | 实现复杂,通常依赖第三方SDK | 反机器注册 |
| 语音验证码 | 电话播报数字 | 适合视障用户 | 成本高,环境噪音影响 | 无障碍辅助 |
(3)后端逻辑:
-
生成验证码字符串,随机算法:
SecureRandom(避免可预测)。 -
图形验证码:Java 标准库:
BufferedImage+Graphics2D绘制;常用开源工具 Kaptcha、Hutool-captcha。 -
存入 session——单体应用,redis——分布式/集群环境(设置过期时间,如 5 分钟)。
-
用户提交时比对,无论成功失败都删除或使原验证码失效(一次性)。
HttpSession session = request.getSession();
session.setAttribute("captcha", code);
session.setMaxInactiveInterval(300); // 5分钟过期
redisTemplate.opsForValue().set("captcha:" + sessionId, code, 300, TimeUnit.SECONDS);
(4)完整验证逻辑
- 客户端请求登录页面 → 后端生成验证码图片,返回给前端,并将正确值保存在服务端。
- 用户输入账号、密码、验证码 → 提交登录请求。
- 后端接收请求:
-
从 session/redis 中取出存储的验证码(并立即删除或标记失效,保证一次性)。
-
比较用户输入是否与存储值一致(忽略大小写)。
-
若不一致,返回错误“验证码错误”。
-
若一致,继续校验用户名/密码。
- 无论验证成功或失败,都删除已使用的验证码,防止重复使用。
(5)安全性:
| 措施 | 作用 |
|---|---|
| 验证码一次性使用(用完即删) | 防止攻击者截获验证码后重复提交 |
| 设置有效期(如5分钟) | 降低验证码被暴力枚举或重放的风险 |
| 频率限制(同一IP/用户每分钟最多请求3次) | 防止恶意生成大量验证码消耗服务器资源 |
| 图形验证码添加干扰线、噪点、变形 | 增加 OCR 识别难度 |
| 使用 HTTPS | 防止中间人攻击窃取验证码图片或明文传输 |
| 验证码不返回前端(不出现在HTML/JSON中) | 避免被爬虫直接读取 |
| 后端校验时忽略大小写(某些场景) | 提升用户体验,但不影响安全性 |
| 对错误次数进行限制(如连续错误5次锁定15分钟) | 防止暴力尝试验证码(4位验证码最多1万种可能,无限制可被穷举) |
2.POST请求data格式
-
application/x-www-form-urlencoded:键值对拼接,如name=Tom&age=18。 -
multipart/form-data:文件上传时使用,支持二进制数据。 -
application/json:REST API 常用,请求体为 JSON 字符串。 -
text/xml:XML 格式(老旧系统)。 -
后端通过
@RequestBody(JSON)或@RequestParam(表单)接收。
3.Spring中Bean的作用域
-
singleton(默认):IoC 容器中只有一个实例,所有地方共享。
-
prototype:每次请求(getBean 或注入)都创建一个新实例。
-
request:每个 HTTP 请求一个实例(仅 Web 环境)。
-
session:每个 HTTP Session 一个实例。
-
application:整个 ServletContext 一个实例。
-
websocket:每个 WebSocket 会话一个实例。
4.数据库事务
-
ACID:原子性、一致性、隔离性、持久性。
-
隔离级别(从低到高):
-
READ UNCOMMITTED(读未提交,脏读)
-
READ COMMITTED(读已提交,不可重复读)
-
REPEATABLE READ(可重复读,幻读,MySQL 默认)
-
SERIALIZABLE(串行化)
-
-
传播行为(Spring):
-
REQUIRED:支持当前事务,没有则新建。
-
REQUIRES_NEW:挂起当前事务,新建事务。
-
NESTED:嵌套事务(利用保存点)。
-
5.数据库(关系型和非关系型)
-
关系型:MySQL、Oracle、PostgreSQL。基于表,支持 ACID、SQL 操作。
-
非关系型(NoSQL):键值存储(Redis)、文档存储(MongoDB)、列存储(Cassandra)、图数据库(Neo4j)。适合高并发、灵活 schema、海量数据。
-
选型:需要强一致性、复杂关联查询 → 关系型;需要高扩展性、快速读写 → NoSQL。
6.TRUNCATE:DDL语句,快速删除表中所有行(不能带 WHERE)。
DELETE:DML,可加条件,逐行删除,可回滚,不重置自增列。
7.字符串转换
-
常见转换:
-
数字转字符串:
String.valueOf(123)或Integer.toString(123)。 -
字符串转数字:
Integer.parseInt("123"),注意捕获NumberFormatException。 -
字符数组 ↔ 字符串:
new String(charArray),str.toCharArray()。 -
编码转换:
new String(bytes, "UTF-8"),str.getBytes("UTF-8")。
-
-
注意:字符串不可变,任何看似修改的操作都会产生新对象。
8.时间显示,给定xxxx秒输出YY:MM:DD:HH:MM:SS
java时间类(超全用法解析)-CSDN博客
https://blog.csdn.net/fate_ze/article/details/155068157
public static String convertSeconds(long seconds) {
// 起始日期:1970-01-01
int year = 1970;
int[] daysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 1. 计算天数及剩余秒数
long days = seconds / 86400;
long remainingSeconds = seconds % 86400;
// 2. 计算年份
while (true) {
int daysInYear = isLeap(year) ? 366 : 365;
if (days >= daysInYear) {
days -= daysInYear;
year++;
} else {
break;
}
}
// 3. 计算月份和日期(注意:days 是当年第几天,0-based)
int month = 1;
while (true) {
int dim = daysInMonth[month - 1];
if (month == 2 && isLeap(year)) dim = 29;
if (days >= dim) {
days -= dim;
month++;
} else {
break;
}
}
int day = (int) days + 1; // 转为 1-based
// 4. 计算时、分、秒
int hour = (int) (remainingSeconds / 3600);
int minute = (int) ((remainingSeconds % 3600) / 60);
int second = (int) (remainingSeconds % 60);
// 5. 格式化输出(YY 取后两位)
int yy = year % 100;
return String.format("%02d:%02d:%02d:%02d:%02d:%02d",
yy, month, day, hour, minute, second);
}
private static boolean isLeap(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
Java API
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
public static String convertSeconds(long seconds) {
LocalDateTime dateTime = LocalDateTime.ofEpochSecond(seconds, 0, ZoneOffset.UTC);
return dateTime.format(DateTimeFormatter.ofPattern("yy:MM:dd:HH:mm:ss"));
}
(三)网络、操作系统
1.子网掩码与同一网络判断
-
子网掩码用于区分 IP 地址的网络部分和主机部分。
-
判断两台主机是否在同一子网:将 IP 地址与子网掩码按位相与,结果相同则属于同一网络。
-
例如:IP1=192.168.1.10,IP2=192.168.1.20,掩码=255.255.255.0,相与结果都是 192.168.1.0,所以同网段。
2.DNS 域名系统,将域名(如 www.baidu.com)解析为 IP 地址。
-
解析过程:浏览器缓存 → 操作系统 hosts 文件 → 本地 DNS 服务器 → 根 DNS → 顶级域 DNS → 权威 DNS。
-
记录类型:A(IPv4)、AAAA(IPv6)、CNAME(别名)、MX(邮件交换)、TXT(文本)。
3.Cookie和Session的区别和联系
| Cookie | Session | |
| 存储位置 | 客户端(浏览器) C/B | 服务器端 S |
| 大小限制 | 通常 4KB | 无固定限制(受内存/存储限制) |
| 安全性 | 较低,可被篡改或窃取 | 较高,存储在服务器 |
| 生命周期 | 可设置过期时间 | 依赖 session 超时或主动销毁 |
| 跨域 | 默认同源,可设置 domain | 通常绑定同一应用 |
-
联系:Session 通常依赖 Cookie 携带 SessionID(如
JSESSIONID)来标识客户端。
4.CPU中跟踪指令后继地址寄存器
-
程序计数器(PC,Program Counter):存储下一条要执行指令的内存地址。
-
当执行一条指令后,PC 自动增加(指向顺序下一条),分支/跳转指令会修改 PC 值
5.sleep,wait,notify
-
sleep(long millis):Thread 静态方法,当前线程休眠,不释放锁。 -
wait():Object 实例方法,必须在 synchronized 块中调用,释放锁并进入等待队列。 -
notify()/notifyAll():唤醒一个/所有等待该对象锁的线程。
6.线程,死锁条件
-
线程创建:继承
Thread,实现Runnable(推荐),或Callable+FutureTask。 -
死锁四个必要条件(缺一不可):
-
互斥:资源一次只能一个线程使用。
-
请求与保持:线程持有资源并等待其他资源。
-
不剥夺:已分配资源不能被强制剥夺。
-
循环等待:多个线程形成等待环路。
-
-
避免:破坏任一条件(如按顺序加锁、使用超时锁)。
7.进程信号量S,P,V
【操作系统原理】信号量及PV操作详解-阿里云开发者社区
https://developer.aliyun.com/article/1251045semaphore s;大于0表示当前可用资源的数量,小于0其绝对值标志等待使用该资源的进程个数
p--wait() s-1 阻塞调用进程
v--signal() s+1 释放/唤醒在条件变量上阻塞的进程
8.线程编码,存钱取钱
Java多线程编程实践——从基础输出到银行账户存取款模拟-CSDN博客
https://blog.csdn.net/ZYN20050813/article/details/155735668
更多推荐
所有评论(0)