Java后端开发 笔试知识点复习(三)
某银行 线上笔试
一、选择题
1.排序算法 是否稳定
稳定性定义:如果两个相等的元素在排序前后的相对位置不变,则称该排序算法是稳定的。
快希选堆不稳定(快排、希尔、选择、堆排序)
| 算法 | 稳定 | 备注 |
| 冒泡排序 | ✅️ | 相邻交换,相等不交换 |
| 插入排序 | ✅️ | 插入时相等元素不越过 |
| 归并排序 | ✅️ | 合并时左边优先 |
| 选择排序 | 交换可能打乱相等元素顺序 | |
| 快速排序 | 分区交换不稳定 | |
| 堆排序 | 堆化过程不稳定 | |
| 希尔排序 | 分组插入,跨步长交换 | |
| 计数排序 | ✅️(稳定实现) | 按顺序收集 |
| 奇数排序 | ✅️ | 稳定子排序保证 |
2.TCP/IP封装顺序,一台主机向另一台主机发送HTTP请求,数据从应用层—传输层—网络层—链路层,首部信息依次添加的顺序:TCP/UDP头部—IP头部—以太网头部。
封装过程:应用层数据(HTTP报文)—传输层添加TCP/UDP头部—网络层添加IP头部—链路层添加以太网头部(含MAC地址)和尾部FCS。
OSI的七层模型:
- 应用层:各种应用程序协议,比如HTTP、HTTPS、FTP、SOCKS安全套接字协议、DNS域名系统、GDP网关发现协议等。
- 表示层:加密解密、转换翻译、压缩解压缩,比如LPP轻量级表示协议。
- 会话层:不同机器上的用户建立和管理会话。比如SSL安全套接字层协议、TLS传输层安全协议、RPC远程过程调用协议等。
- 传输层:接受上一层的数据,在必要时对数据进行分割并交给网络层,保证这些数据有效到达对端,比如TCP传输控制协议、UDP数据报协议。
- 网络层:控制子网的运行:逻辑编址、分组传输、路由选择,比如IP、IPV6、SLIP等。
- 数据链路层:物理寻址,同时将原始比特流转变为逻辑传输路线,比如XTP压缩传输协议、PPTP点对点隧道协议等。
- 物理层:机械、电子、定时接口通信信道上的原始比特流传输,比如IEEE802.2等。
TCP/IP的四层网络模型:
- 网络接口层:用于协作IP数据在已有网络介质上传输的协议,ARP地址解析协议(IP地址解析为MAC地址),RARP反向地址解析协议(MAC地址解析为IP地址)。
- 网间层:对应网络层,负责数据的包装、寻址和路由。同时还包含网间控制报文协议ICMP用来提供网络诊断信息。IP,RIP,ICMP。
- 传输层:对应传输层,提供两种端到端的通信服务。TCP提供可靠的数据流运输服务,UDP提供不可靠的用户数据报服务。
- 应用层:对应应用层和表达出。Finger、Whois、FTP文件传输协议、Gopher、HTTP超文本传输协议、Telent远程终端协议、SMTP简单邮件传送协议、IRC因特网中继会话、NNTP网络新闻传输协议。
3.信号量。P,V的信号量初值S为2,当前值为2,哪个会唤醒进程(V后信号量值<=0,说明有进程在等待,需要唤醒)?
P操作:S减一,若S<0则阻塞,获取资源。
V操作:S加一,若S<=0则唤醒一个等待进程,释放资源。
一个线程 PV,两个线程 PV PV。
我们计算每个序列执行后的最终S值,并判断中间是否有V操作导致S<=0。
-
PPVPPV:P(2→1), P(1→0), V(0→1, 1>0不唤醒), P(1→0), P(0→-1阻塞), V(-1→0, 此时S=0<=0,唤醒一个) → 有唤醒。
-
PPVPVV:P(2→1), P(1→0), V(0→1), P(1→0), V(0→1), V(1→2) → 没有S<=0的情况,无唤醒。
-
PVPVPV:P(2→1), V(1→2), P(2→1), V(1→2), P(2→1), V(1→2) → 无阻塞无唤醒。
-
PVPPVV:P(2→1), V(1→2), P(2→1), P(1→0), V(0→1), V(1→2) → 无唤醒。
4.二叉树 先序遍历(根左右),中序遍历(左根右),后序遍历(左右根)
5.SQL,年龄最大的前3个人,SELECT * FROM person ORDER BY age DESC LIMIT 3;
6.IaaS、PaaS、Saas
-
IaaS(基础设施即服务):提供计算、网络、存储等基础资源。用户可部署任意软件,控制OS、存储、应用程序,支持自定义配置。虚拟机,云服务器。数据库服务、预装OS和应用属于IaaS吗?——如果是用户自己安装数据库,属于IaaS;如果是托管数据库服务(如RDS),则更接近PaaS。
-
PaaS(平台即服务):提供开发部署平台,用户只管应用,不管OS和中间件。数据库托管,如阿里云RDS。
-
SaaS(软件即服务):直接使用软件,如Gmail、钉钉。
7.数据库隔离级别:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | ✅ 可能 | ✅ 可能 | ✅ 可能 |
| 读已提交 | ❌ | ✅ 可能 | ✅ 可能 |
| 可重复读 | ❌ | ❌ | ✅ 可能(InnoDB的RR通过间隙锁避免了幻读) |
| 串行化 | ❌ | ❌ | ❌ |
并发事务会导致的问题:脏读(读到其他事务未提交的数据)、丢失修改(后写的覆盖先写的)、不可重复读(两次读取,结果不一样)、幻读(两次读取,行数不一样)。
8.设计模式:
- 创建型(单例、原型、工厂方法、抽象工厂、建造者)
- 结构型(代理、适配器、桥接、装饰器、外观、享元、组合)
- 行为型(模版方法、策略、命令、责任链、观察者、中介者、迭代器、访问者、备忘录、解释器)
单例模式:单例对象的类必须保证只有一个实例存在,整个系统只能使用一个对象实例。不会频繁地创建和销毁对象,浪费系统资源。懒汉模式(非线程安全,用的时候再创建对象),饿汉模式(线程安全,提前就已经加载好的静态static对象),双重检查模式(线程安全,两次检查避免多线程造成创建了多个对象)。
(静态)工厂模式:建立一个工厂类,对实现了同一接口的一些类进行实例的创建。客户端只用知道参数就可以创建类;不易拓展。
抽象工厂模式:在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定。只声明方法,具体的实现交给子类(子工厂)去实现。
建造者模式:将一个复杂对象的创建过程与其最终表示形式分离,使得同样的构建过程可以创建出不同结构或配置的对象。
代理模式:给某一个对象提供一个代理,并由代理对象控制对原对象的引用,重在访问权限的控制。能够协调调用者和被调用者,降低了系统的耦合度,可以灵活地隐藏和增加被代理对象的功能和服务;但程序性能没有直接调用性能高,提高了代码的复杂度。
多线程环境下的配置管理器,配置数据在整个应用程序中只有一份,首次访问是懒加载初始化,同时考虑线程安全与性能。——单例模式
9.继承:子类不可直接访问父类私有成员,需通过protected/public方法;子类可继承父类所有成员,可重写方法并扩大访问权限(但不能缩小);创建子类示例,先父类构造函数,子类构造器第一行隐式super()。
10.Transformer架构:Encoder(Self-Attention+FFN+Add&Norm),Decoder
11.寻址:指令中如何找到操作数(或操作数的地址)的方法。
| 操作数所在位置 | 指令中的地址码含义 | 示例(类似汇编) | 特点 |
|---|---|---|---|
| 立即寻址 | 指令本身 | 操作数本身(常数) | MOV AX, 1234H |
| 直接寻址 | 内存 | 操作数的内存地址 | MOV AX, [2000H] |
|
寄存器直接寻址 (简称寄存器寻址) |
寄存器 | 寄存器编号 | MOV AX, BX |
| 寄存器间接寻址 | 内存 | 寄存器中存放的是操作数的地址 | MOV AX, [BX] |
| 基址寻址 | 内存 | 基址寄存器 + 偏移量 | MOV AX, [BX+100] |
12.主键索引查询,主键索引(a,b,c),a=1且b>2 可以,a>2且b=9 不可以。
联合索引遵循最左前缀原则,范围查询(>, <, between, like 'xx%')会停止匹配后续列。
13.软件工程中的“方法”要素:过程、技术、工具、表示法。
软件工程三要素:
| 方法 |
|
| 工具 |
设计建模:draw.io、Visio 编码开发:IDE(IntelliJ IDEA、Eclipse、VSCode)、Git、Maven/Gradle 测试:JUnit、Postman、Swagger 持续集成:GitLab CI、GitHub Actions 文档协作:Notion、Wiki、Markdown编辑器 |
| 过程 |
常见软件过程模型:
|
14.依赖倒置原则(DIP):高层模块不应该依赖低层模块,两者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。面向接口编程,而非实现编程。降低耦合,提高扩展性。高层与低层的耦合——抽象接口+依赖注入
开闭原则(OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。需求变化导致的代码修改——抽象+多态扩展
里氏替换(LSP):子类型必须能够替换掉它们的父类型。即程序中所有使用父类对象的地方,都可以透明地替换成子类对象,而不会改变程序的正确性。继承的正确使用
15.栈:先入后出;队列:先入先出
二、编程题
1.Java计算,double与int乘,输出保留两位小数,开n次方
double与int乘:自动类型提升为double。
保留两位小数:
-
String.format("%.2f", value) -
BigDecimal.setScale(2, RoundingMode.HALF_UP)
Math:
-
a的b次方:使用
Math.pow(a, 1.0/n)。注意:Math.pow(8, 1.0/3)得到2.0。 -
绝对值:abs(x) 支持int/long/float/double
-
最大/最小值:max(a,b)/min(a,b)
-
平方根:sqrt(x)
-
随机数:Math.random() // [0.0, 1.0) 的double
-
指数与对数:
Math.exp(x); // e^x Math.log(x); // 自然对数 ln x Math.log10(x); // 以10为底的对数
-
取整:
double x = 3.6; Math.ceil(x); // 向上取整 → 4.0 Math.floor(x); // 向下取整 → 3.0 Math.round(x); // 四舍五入 → 4(返回long) Math.rint(x); // 四舍五入取整(返回double,逢 .5 取偶数) -
BigDecimal:用于精确货币计算,避免浮点误差。
-
比较:
a.compareTo(b) > 0表示 a > b。=0表示a=b,不要用equals比较2.0和2.00(scale不同返回false) -
加减乘除:a.add(b),a.subtract(b)
,a.multiply(b),a.divide(b, 2, RoundingMode.HALF_UP)。 -
取负:a.negate()
-
绝对值:a.abs()
-
stripTrailingZeros()– 去除末尾多余的0 -
toPlainString()– 返回不带指数形式的字符串 -
scale()– 返回小数位数
-
-
全额降序排序 Comparator
List<Item> list = ...; list.sort((o1, o2) -> o2.getAmount().compareTo(o1.getAmount())); // 或使用 Comparator.reverseOrder()
2.String
-
String取子串:
-
substring(beginIndex, endIndex):注意 endIndex 是不包含的。 -
取最后4个字符:
str.substring(str.length() - 4)。 -
取前3个字符:s.substring(0, 3);
-
-
大小写转换:
str.toUpperCase();str.toLowerCase() -
转换与修改:String不可变,返回新字符串
String upper = s.toUpperCase();
String lower = s.toLowerCase();
String trimmed = s.trim(); // 去除首尾空白
String replaced = s.replace('l','w'); // 替换字符
String replacedAll = s.replaceAll("\\d+", "#"); // 正则替换
String[] parts = s.split(","); // 分割
String sub = s.substring(2, 5); // [2,5) 子串
String joined = String.join("-", "a","b","c"); // "a-b-c"
-
格式化
String fmt = String.format("姓名:%s,年龄:%d", "张三", 25);
System.out.print(fmt);
//姓名:张三,年龄:25
// 或使用 printf
System.out.printf("%.2f\n", 3.14159);
//3.14
-
查询与判断:
| 方法 | 示例 | 说明 |
|---|---|---|
length() |
s.length() |
字符个数 |
charAt(int) |
s.charAt(0) |
获取指定位置字符 |
indexOf(String) |
s.indexOf("lo") |
子串首次出现位置 |
lastIndexOf(String) |
最后一次出现位置 | |
contains(CharSequence) |
s.contains("he") |
是否包含子串 |
startsWith(String) |
是否以某前缀开头 | |
endsWith(String) |
是否以某后缀结尾 | |
isEmpty() / isBlank() |
是否为空或仅空白(Java 11+) | |
equals(Object) |
s1.equals(s2) |
内容相等 |
equalsIgnoreCase(String) |
忽略大小写比较 |
-
StringBuilder:线程不安全,效率高(单线程推荐)
-
StringBuffer:线程安全,效率略低(多线程环境)
3.格式化语法
格式化字符串包含普通文本和格式说明符(以 % 开头)。
基本语法:%[参数索引$][标志][宽度][.精度]转换符
常见转换符(必须掌握)
| 转换符 | 说明 | 示例 |
|---|---|---|
%s |
字符串 | "姓名:%s" → 填入 String |
%d |
十进制整数 | "年龄:%d" → 填入 int / long |
%f |
浮点数(十进制) | "价格:%.2f" → 保留两位小数 |
%e / %E |
科学计数法 | "科学计数:%e" |
%x / %X |
十六进制整数 | "十六进制:%x" |
%o |
八进制整数 | "八进制:%o" |
%c |
字符 | "等级:%c" → char |
%b |
布尔值 | "是否通过:%b" → true/false |
%n |
平台独立的换行符 | 相当于 \n 但跨平台更好 |
%% |
输出百分号本身 | "成功率:100%%" → 输出 "100%" |
常用标志与宽度(让输出更整齐)
| 标志 | 作用 | 示例 |
|---|---|---|
- |
左对齐(默认右对齐) | "%-5d" → 整数占5格,左对齐 |
0 |
数字前面补0 | "%05d" → 5 → 00005 |
, |
数字千位分隔符 | "%,d" → 1234567 → 1,234,567 |
+ |
强制显示正号 | "%+d" → 5 → +5 |
( |
负数用括号括起来(财务风格) | "%(d" → -5 → (5) |
空格 |
正数前加空格,负数前加负号 | "% d" |
宽度:最小字符数,不够则用空格填充(默认右对齐)。
精度:
-
对于
%f:小数点后位数 -
对于
%s:最大字符数(截断)
// 左对齐,宽度10,保留2位小数
System.out.printf("%-10.2f", 123.456); // 输出 "123.46 "(后面有空格)
// 补零,宽度6
System.out.printf("%06d", 42); // 输出 "000042"
// 千位分隔符 + 两位小数
System.out.printf("%,.2f", 1234567.891); // 输出 "1,234,567.89"
更多推荐




所有评论(0)