机器人Java后端算法笔试题解析

  1. 如何判断一个字符串变量a为空,包括null、空字符串、一个或多个空格、一个或多个whitespace?

if (a == null || a.isBlank()) {

}

  1. Java新版本为什么要添加Instant?

Java 8 引入 Instant 主要是为了修复旧版日期时间类(如 java.util.Date)的设计缺陷,

原因如下:

  1. 不可变性与线程安全

Instant 是不可变的(Immutable),天然线程安全;

Date 是可变的,在多线程环境下容易产生并发问题。

  1. 更高精度

Instant 支持纳秒级 10\^{-9} 秒)精度;

Date 只能精确到毫秒。

  1. 语义清晰(机器时间)

Instant 明确表示 UTC 时间线上的瞬时点(timestamp),语义清晰,适合机器时间处理(日志、分布式时间戳、事件时间);

而 Date API 设计混乱,日期计算与格式化常依赖 Calendar、TimeZone 等类,易产生时区问题。

  1. 如何判断两个double类型的变量是否相等?例如doublea=1.2;doubleb=1.1 +0.1; 比较a和b是否相等。
java 复制代码
public static boolean nearlyEqual(double a, double b, double epsilon) {
    return Math.abs(a - b) < epsilon;
}

// 使用
double a = 1.2;
double b = 1.1 + 0.1;
boolean equal = nearlyEqual(a, b, 1e-9);  // true
//epsilon 的取值取决于业务精度要求,常见取 1e-9 到 1e-6。
  1. 下面三条语句是否是合法的,如果不是原因是什么?
java 复制代码
List<String> a = new ArrayList<String>();//1
List<Object> a = new ArrayList<String>();//2
List<?> a = new ArrayList<String>();//3

1.合法:左右类型完全匹配。

2.不合法:Java 泛型具有不变性,List 与 List 不存在父子关系。

若允许赋值,可通过 List 写入非 String 类型,破坏类型安全。

3.合法:? 是无界通配符,代表未知类型,ArrayList 是 List<?> 的子类型。

但由于类型未知,只能读取不能写入(null 除外),因此编译器允许。

  1. 一个字符串String,如何转换为字节数组。反过来呢?
java 复制代码
//1.String → byte[]
String str = "CodeEdge_Xu";

// 显式指定编码(避免平台差异)
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);

//2.byte[] → String
byte[] bytes = ...;

// 与编码时保持一致
String str = new String(bytes, StandardCharsets.UTF_8);
  1. Java中,如果对象有循环引用,能否被GC。比如Path类里面有个字段reversedPath反向字段。两个Path对象因为这个字段相互引用。如果不能被GC,怎么解决。

能。

Java 主流 GC(G1、ZGC、CMS)用的是可达性分析,不是引用计数。

只要这两个 Path 对象整体从 GC Roots 不可达,循环引用不影响回收。

真正导致不能 GC 的是外部强引用,比如:静态字段持有,ThreadLocal 未 remove,未注销的监听器。

解决办法

一般不需要特殊处理。

只要外部强引用断开,对象整体从 GC Roots 不可达即可回收。

真正的问题是被静态变量、线程、缓存、监听器等长期持有。

  1. 写正则表达式,从类似"10,12;A1@12|12:23|p=1|f=2"字符串中抽出变量:"{x},{y};{name}@{index}|{timeStart}|{timeEnd}p={id}"。其中,除了name外其余均是数字,name中有数字、字母、中划线、下划线。
java 复制代码
Pattern pattern = Pattern.compile(
    "^(\\d+),(\\d+);([A-Za-z0-9_-]+)@(\\d+)\\|(\\d+:\\d+)(?:\\|(\\d+:\\d+))?\\|p=(\\d+)\\|f=(\\d+)$"
);
  1. 什么是大端(Big-endian),什么小端(Little-endian)?网络传输一般是大端还是小端?

大端:高位字节放前面,低位放后面。

小端:低位字节放前面,高位放后面。

网络传输一般是大端

TCP/IP 协议规定数据包中的多字节整数必须按大端传输。

  1. 一个整数变量,如果只有一个线程修改它,但有多个线程读取它,有线程安全问题吗?

有线程安全问题,主要是可见性问题。

写线程修改后的值,其他线程不一定能立刻看到,可能一直读取旧值,因此通常需要使用 volatile 或同步机制保证可见性。

对于 long/double,早期 JVM 还存在非原子读写问题(现代 JVM 通常已解决)。

10 . Java的线程能被强制杀死吗?

不能安全地强制杀死。

Thread.stop() 可以强制终止,但已废弃(deprecated),因为会立即释放锁,导致对象状态损坏、资源泄漏。

11 . 如果想要一个线程安全的List,可以用List的哪些实现,或通过什么手段实现。

方式 特点
Vector 古老类,所有方法 synchronized,已不推荐
Collections.synchronizedList(new ArrayList<>()) 包装器,全表锁,读也串行
CopyOnWriteArrayList 读多写少首选,写时复制新数组,读无锁
手动加锁 synchronizedReentrantReadWriteLock,灵活但代码重

12 . 有一个List,其中的元素是监听器对象。在多线程环境下,需要对这个List进行添加、删除和遍历三个操作,如何线程安全地进行?除了对添加、删除和遍历加锁或同步的方式------因为如果对遍历加同步,可能会阻塞很长时间,因为遍历一遍可能要很久,会阻塞添加、删除等操作,也会阻塞其他线程的遍历操作。

CopyOnWriteArrayList

它内部写操作(add/remove)时复制一份新数组,修改完后替换引用;

读/遍历直接读当前数组快照,完全不加锁

所以遍历不会阻塞添加、删除,也不会阻塞其他线程遍历。

迭代器基于快照,不会抛 ConcurrentModificationException

13 . Java核心库中创建线程池的方法是?通过核心库的线程池实现并发,比new Thread有哪些好处?

工具类工厂方法

使用 java.util.concurrent.Executors 提供的静态方法(如 newFixedThreadPoolnewCachedThreadPoolnewSingleThreadExecutor 等)。

直接构造对象

通过 new ThreadPoolExecutor(...) 手动创建。

推荐直接使用 ThreadPoolExecutor 手动指定核心线程数、最大线程数、队列长度和拒绝策略,而不是直接使用 Executors 工厂方法,因为部分默认实现可能导致 OOM。
new Thread 的好处

  • 降低资源消耗 :通过复用已创建的线程,减少频繁创建和销毁线程的 CPU 和内存开销。
  • 提高响应速度:任务到达时,无需等待线程创建即可立即执行。
  • 提高线程可管理性:能统一分配、调优和监控线程,防止无限制创建线程导致系统资源耗尽(如 OOM)。

14 . MySQL中,varchar(100)的列,能存多少个英文字母?多少个汉字?使用utf8mb4字符集。

100 个英文字母,100 个汉字。

MySQL 的 varchar(100)100 是字符数,不是字节数

utf8mb4 下英文字母通常 1 字节,中文常见汉字一般 3 字节,部分扩展字符可能占 4 字节,但 varchar(100) 限制的是字符数,因此最多依然存 100 个字符。

15 . MySQL中,datetime和timestamp有何不同,精度分别是毫秒还是秒,是否有时区?

datetime:

  • 范围大(1000~9999 年)
  • 不涉及时区
  • 默认精度到秒
  • 支持小数秒 datetime(fsp),最多微秒(6位)

timestamp:

  • 范围小(1970~2038 年)
  • 有时区语义(存 UTC,读时按 session timezone 转换)
  • 默认精度到秒
  • 支持 timestamp(fsp),最多微秒(6位)

16 . 写SQL:

订单表wms_order,单行表wms_order_line,一对多关系。

wms_order表有列id(单号)、create_on(创建时间)等字段,

wms_order_line有id、order_id(所属订单)、line_no(行号)、product_id (商品 ID)。

如何查询2021年12月内发生的含有A、B、C三个商品的订单。

sql 复制代码
SELECT o.id AS order_id, o.create_on
FROM wms_order o
INNER JOIN wms_order_line ol ON o.id = ol.order_id
WHERE 
  -- 筛选2021年12月的订单
  o.create_on >= '2021-12-01' 
  AND o.create_on < '2022-01-01'
  -- 筛选包含A、B、C任意一个商品的行
  AND ol.product_id IN ('A', 'B', 'C')
GROUP BY o.id, o.create_on
-- 确保订单同时包含这3个不同的商品
HAVING COUNT(DISTINCT ol.product_id) = 3;

17 . 如果有一张订单表,查询量最大的查询条件有两种:

  • 根据某个创建人和创建时间(范围)查询。
  • 根据某个类型和创建时间(范围)查询。

建议如何建立索引?

建立两个联合索引,并遵循"等值查询字段在前,范围查询字段在后"的原则:

  1. 索引一(创建人, 创建时间)
  2. 索引二(类型, 创建时间)

理由

  • 最左匹配原则:将等值条件(创建人/类型)放在首位,范围条件(时间)放在末位,可以使索引效率最高。
  • 覆盖查询:联合索引可提高过滤效率;若查询字段被索引完全覆盖,还可减少回表。

18 . @Resource@Autowired@Inject的区别?

特性 @Autowired @Resource @Inject
来源 Spring 框架专用 JSR-250 JSR-330
默认匹配方式 按类型 (byType) 先 byName,再 byType 按类型 (byType)
找不到对应 Bean 报错(可设置 required=false 报错 报错
指定特定名称 配合 @Qualifier 使用 name 属性 配合 @Named
注入位置 构造器、字段、Setter、方法 字段、Setter 构造器、字段、Setter

19 . @Transactional可以用于private方法吗,为什么?

private 方法不能生效,因为 Spring AOP 无法代理 private 方法;

其不能被子类覆盖,因此代理对象无法拦截。

同类内部 this.xxx() 调用也会绕过代理,因此事务同样不生效。

20 . 支付宝等接口,要求请求中对字段做签名,目的是什么?常见的签名算法有哪些?

目的

保证请求数据不被篡改 ,并证明请求方身份(只有持有密钥的一方才能生成有效签名)。

常见签名算法

算法 说明
RSA2 / SHA256withRSA 主流,支付宝等常用,私钥签名、公钥验签
RSA / SHA1withRSA 旧版兼容,安全性弱于 RSA2
HMAC-SHA256 双方共享密钥,常用于微信支付等
MD5 早期接口(如旧版支付宝),已不推荐,不安全
SM2 国密算法,政务/金融国产化场景

21 . 一种常见的攻击手段是huge body,比如请求报文是JSON,但构造一个很大的JSON字符串,几百M甚至几个G,解析JSON会把CPU干爆,甚至把内存用光。在Java体系下(Java Servlet、使用Spriing或不使用),在哪一层怎么解决这个问题。

huge body 应采用分层治理,越靠前拦截越好:

  1. 网关 / Nginx 层(优先级最高)
    限制请求体大小,例如:
    client_max_body_size 10m;
    超限直接返回 413,避免请求进入 Java 应用。
  2. 容器层(Tomcat/Jetty/Undertow)
    限制 HTTP 请求体大小,例如 Tomcat:
    maxPostSize="10485760"
    防止超大 body 被 Servlet 容器接收。
  3. 应用层(Spring / Servlet)
    避免 @RequestBody 直接全量反序列化大 JSON。
    可先检查 Content-Length,
    或使用 Jackson JsonParser 流式解析(Streaming API),边读边处理,避免一次性占用大量内存。
  4. 安全治理
    结合限流、超时、熔断,防止 DoS 攻击持续消耗 CPU 与内存。

22 . 把用户的密码明文存储到数据库里是不好的,那么如何存储比较好?

采用 加盐哈希 (Salted Hashing) 存储,具体做法如下:

  1. 使用强散列算法 :不要使用 MD5 或 SHA-1(易破解),推荐使用 Argon2BCryptSCrypt
  2. 添加随机盐值 (Salt):为每个用户生成一个唯一的、随机的"盐",与密码拼接后再哈希。防止彩虹表攻击。
  3. 增加工作因子 (Work Factor):通过调整迭代次数增加计算耗时,抵御暴力破解。
  4. 禁止可逆加密:密码应单向加密,不可被还原。

某些高安全场景还会增加 pepper(系统级密钥),保存在服务端配置或密钥系统中,而不是数据库。

相关推荐
我是一颗柠檬2 小时前
【JDK8新特性】函数式接口Day2
java·开发语言·后端·intellij-idea
Bat U2 小时前
JavaEE|JVM
java·jvm·java-ee
运筹vivo@2 小时前
3043. 最长公共前缀的长度(Leetcode 每日一题)
c++·算法·leetcode·职场和发展·每日一题
Mahir082 小时前
Spring Boot 自动装配深度解密:从原理到自定义 Starter 实战
java·spring boot·后端·自动装配·自定义starter·大厂面试题
淘源码d2 小时前
产科系统源码,数字产科源码,Java(后端) + Vue + ElementUI(前端) + MySQL(数据库),确保系统稳定性与扩展性。
java·源码·数字产科·产科系统·智能化孕产服务·高危五色预警·智慧产科
AI云原生2 小时前
远程控制软件进入协作阶段:ToDesk、向日葵、AnyDesk、RustDesk怎么选?
运维·服务器·网络·windows·docker·云原生·开源软件
wand codemonkey3 小时前
SpringbootWeb【入门】+MySQL【安装】+【DataDrip安装 】+【连接MySQL】
java·mysql·mybatis
Mahir0811 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
RyFit12 小时前
SpringAI 常见问题及解决方案大全
java·ai