news 2026/10/30 12:18:25

金融科技Java笔试题核心考点拆解:集合、并发、JVM与Spring

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
金融科技Java笔试题核心考点拆解:集合、并发、JVM与Spring

简介:2020兴业数金Java笔试题.docx是一份针对兴业银行旗下兴业数金Java在线笔试整理的问答式复习资料,适合备战银行金融科技岗位Java笔试的求职者使用。文档以知识点问答形式呈现,重点覆盖Java方法重载、JDK提供的javadoc/jar/jconsole等辅助工具及各自用途、计算机存储系统的Cache-主存-辅存三级层次与分层原因、多线程同步和互斥的用户模式与内核模式实现方式、MySQL中InnoDB引擎的事务与行级锁机制、最近对称数的编程求解、Delete与Truncate的差别,以及堆的数据结构特点,这些均为笔试常见高频考点。压缩包内共1个docx文档,大小仅14KB,内容精炼,便于快速翻阅和考前记忆。该资源已有8735人学习下载,关注度较高。通过这份总结,可以快速梳理Java笔试核心知识脉络,并针对薄弱环节进行查漏补缺,尤其适合备考时间紧张、需要集中回顾重点的开发者。

1. 一份 2020 年的Java笔试题,为什么今天还值得逐题拆

事情很简单:某开发者最近在准备金融科技方向的Java岗位面试,翻出一份“2020 兴业数金Java笔试题.docx”的老题集。起初他觉得年代久远、参考价值有限,结果认真做了一遍发现——题目里考的东西,恰恰是现在很多面试者最心虚的部分:集合的底层结构、并发工具的真实行为、JVM参数的业务含义,而不是网上刷烂了的八股背诵。

这让我想明白一件事:金融类公司的Java笔试题,风格上普遍不追新框架、不考冷门API,而是把Java基础、并发、数据库和Spring这几块往深里问。因为这类系统对稳定性、数据一致性和故障排查的要求极高,笔试的目的不是筛掉不会用新特性的人,而是筛掉对基础机制理解不透的人。2020年的题和当下的考察方向高度重合,甚至可以说,把这份题吃透,比盲目刷几十道LeetCode更接近这类公司的真实门槛。

这篇文章不贴原题原文,而是围绕这份笔试题暴露出来的技术板块,拆成一套可以照着复习和自测的路径:先看核心考点和出题意图,再逐步深入到集合源码、并发与JVM、数据库与Spring,最后用真实的踩坑记录告诉你哪些地方最容易翻车。无论你是准备笔试的在校生,还是想转金融科技方向的在职开发者,这份拆解都值得花一个周末认真过一遍。

2. Java基础与集合框架:笔试题里的“送分题”其实最拉分

2.1 HashMap的底层结构:从数组到红黑树,面试官到底在考什么

金融科技公司的笔试题里,HashMap几乎是必考项,而且很少只考“HashMap底层是数组加链表”这种一句话答案。更多是给一段代码让你推断扩容时机,或者问为什么Java 8要把链表转成红黑树。这些问题背后的核心,是考察你对哈希冲突、负载因子和树化阈值这三者关系的理解。

HashMap的默认负载因子是0.75,默认初始容量是16。当元素数量超过容量乘以负载因子时,触发扩容,容量翻倍。为什么选0.75而不是0.5或者1?这是时间与空间的折中:负载因子太小,空间浪费严重;太大,哈希冲突概率升高,链表的查询效率会变差。而在Java 8之后,当链表长度超过8且数组容量大于等于64时,链表会树化为红黑树,目的是把极端情况下的查询时间复杂度从O(n)降到O(log n)。

笔试里常考的一个点:为什么树化阈值是8而不是其他数字?源码注释里给出的解释是泊松分布——在随机哈希码下,链表长度达到8的概率已经极低,约千万分之一。这个数字既保证了正常场景下链表足够高效,又能在极端攻击(构造恶意哈希码)下有兜底方案。我一般会建议复习时把源码注释这段也读一遍,笔试时能写出“泊松分布”四个字,比单纯背阈值数字更有说服力。

另一个高频点是HashMap的扩容机制。JDK 7的扩容是头插法,并发下可能形成环形链表,导致死循环;JDK 8改为尾插法,解决了这个问题,但并发下仍然丢失数据。这道题的深意在于:面试官想听你说出“HashMap线程不安全,并发场景要用ConcurrentHashMap”,并进一步解释ConcurrentHashMap的锁粒度设计。

2.2 手写equals和hashCode:笔试题里最容易“看似会、一写就错”的代码

Java基础部分的笔试题,经常让你手写一个类的equals和hashCode方法,或者给一段代码问你两个对象为什么相等。这个考点折磨人的地方在于:它不需要你背任何API,但要求你对契约关系有完整的认知。

equals方法要满足自反性、对称性、传递性、一致性和非空性。手写时最常见的错误是忘记判空、忘记类型判断,或者用了instanceof但没处理子类对称性问题。hashCode的规范更严格:两个对象如果equals相等,hashCode必须相等;如果hashCode不等,equals一定不相等。动hashCode不影响equals,但动equals几乎必然要求重写hashCode。

我见过一道很典型的笔试题:一个类只有id字段参与equals比较,但hashCode用了所有字段生成。结果是两个id相同但其他字段不同的对象,equals返回true,hashCode却不相等。把这两个对象放进HashSet,两个都能存进去,因为HashSet先算hashCode定位桶,再调用equals比较。这个现象在HashMap、HashSet、ConcurrentHashMap里都会引发数据冗余甚至逻辑错误。

对应的代码解析:

public class User { private Integer id; private String name; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return Objects.equals(id, user.id); } @Override public int hashCode() { // 必须只使用参与equals比较的字段生成哈希码 return Objects.hash(id); } }

重点说明:equals里用getClass()而不是instanceof,是为了避免子类对象和父类对象相等时的对称性破坏。hashCode方法里的注释是这类题目的关键——如果注释里写“只使用id”,说明你理解hashCode必须与equals保持字段一致;如果写“所有字段都参与”,那这道题大概率要扣分。

笔试中还有一个高频变体:用HashSet存储自定义对象后,修改了参与hashCode计算的字段。这会导致对象的hashCode变化,但它在HashSet里的存储位置不会变,于是出现“对象在集合里,但用contains方法找不到”的诡异现象。这算是笔试题里的进阶坑,后面避坑章节会展开讲。

2.3 String、StringBuilder和StringBuffer:线程安全题的“三兄弟”

String相关的题目在笔试题里永远不会缺席,但金融公司考的花样更多,经常把字符串拼接的性能对比和线程安全放在一起考。String是不可变的,每次拼接都会生成新对象;StringBuilder是可变且线程不安全的;StringBuffer是可变且线程安全的——但线程安全的代价是方法加了synchronized,性能比StringBuilder差。

笔试题更常见的出法,是给你一段循环拼接的代码,问性能差异,或者让你判断某种写法会创建多少个对象。比如“String s = new String("abc")”创建了几个对象,答案是1个或2个——如果常量池里已有"abc"则是1个,否则是2个。这类题考察的不仅是语法,还有JVM常量池机制的掌握程度。

真正的分水岭题目是:一段代码里同时出现String拼接和Integer缓存。比如:

Integer a = 128; Integer b = 128; System.out.println(a == b); // false Integer c = 127; Integer d = 127; System.out.println(c == d); // true

原因在于Integer的缓存范围是-128到127,在这个范围内直接返回缓存对象,超出则新建对象。这个问题本身不难,但它和String常量池、基本类型自动装箱放在一起考时,很多人在紧张状态下会混淆“对象相等”和“值相等”的概念。

3. 并发编程与JVM:金融系统最看重的一块硬功夫

3.1 线程池参数:笔试题让你算“核心线程数”,实际是在问业务场景

并发相关的笔试题里,线程池是最大热门,尤其是ThreadPoolExecutor的七个参数。多数人能背出corePoolSize、maximumPoolSize和workQueue,但一问到“一个任务是先进队列还是先创建新线程”就卡住了。实际规则是:当提交任务时,如果当前线程数小于核心线程数,创建新线程执行;如果达到核心线程数且队列未满,任务进队列;如果队列满了但线程数小于最大线程数,创建新线程;如果线程数已达到最大值且队列也满了,触发拒绝策略。

这个执行顺序你必须倒背如流,因为它直接决定了线程池在高并发下的行为模式。笔试题常这样出:核心线程数5,最大线程数10,队列容量100,提交了20个任务,问当前活跃线程数和队列里的任务数。很多人默认“先创建线程到10再排队”,实际答案是:前5个任务创建线程,后15个任务全部进队列,活跃线程数仍是5。

关于核心线程数的设置,业界有两个派别。CPU密集型任务设置为核心线程数等于CPU核数加一或两倍CPU核数;IO密集型任务因为线程大部分时间在等待,可以设置更多,常见做法是两倍CPU核数或更高。但笔试里如果出现具体业务场景,你得先判断任务是CPU密集还是IO密集——金融系统里大量场景是高并发短IO操作,线程数往往可以比CPU核数大很多。

一个非常典型的题目:假设一个系统需要处理每秒1000个请求,每个请求平均耗时200ms,其中IO等待150ms,CPU计算50ms。这个场景下线程数应该如何估算?按照“线程数 = CPU核数 * (1 + 等待时间 / 计算时间)”的公式,如果是4核机器,理论值是4 * (1 + 150 / 50) = 16个线程。这道题不是让你背公式,而是在考察你是否理解“线程不是越多越好,线程切换本身有开销”。

3.2 synchronized与ReentrantLock:从锁升级到可中断,笔试的深度分界线

synchronized和ReentrantLock的对比是并发笔试题的保留节目。基础层面的区别大家都能说:前者是关键字,后者是API;前者自动释放锁,后者必须手动释放;前者非公平,后者可以选公平或非公平。但真正拉开差距的是对synchronized锁升级机制的理解。

JDK 6之后synchronized引入了偏向锁、轻量级锁和重量级锁的升级路径。偏向锁针对“只有一个线程访问同步块”的场景,减少CAS开销;一旦有第二个线程竞争,升级为轻量级锁,通过CAS自旋获取锁;自旋超过阈值或竞争加剧,升级为重量级锁,进入操作系统内核的互斥量。笔试题如果问“为什么synchronized性能不比ReentrantLock差”,你得能说出锁升级和自适应自旋这两点。

ReentrantLock的价值在于它提供了synchronized没有的能力:可中断、可超时、公平锁、多条件变量。面试常问的一个场景:一个线程获取不到锁时,希望等待一段时间后放弃而不是一直阻塞,ReentrantLock的tryLock(long timeout, TimeUnit unit)就是干这个的。金融系统里做分布式任务调度时,这种“获取不到锁就快速失败”的模式非常常见。

Condition是另一个容易出多选题的知识点。ArrayBlockingQueue的底层就是用Condition实现了“队列满时生产者等待”和“队列空时消费者等待”两个条件变量。笔试考到这里,已经不只是背API,而是要求你能读懂一个并发容器的源码级实现。

3.3 JVM内存区域与GC:笔试题爱问“对象在哪分配”,实际在考你排查OOM的能力

JVM部分的笔试题,通常考内存区域划分、对象分配流程和垃圾回收器选择。基础题是问堆、栈、方法区、程序计数器和本地方法栈各自存什么。进阶题是给一段代码问对象创建过程——比如new一个对象时,JVM经历了类加载、内存分配、初始化、设置对象头等步骤。

更贴近实战的考法是给一个GC日志或内存Dump,让你判断是堆内存溢出还是栈内存溢出、是内存泄漏还是内存不足。金融公司特别爱考这类题,因为线上系统OOM是必须能独立排查的问题。

一个常见题目:一段代码往ArrayList里不断添加大对象,最终抛出OutOfMemoryError: Java heap space。问怎么定位。正确答案不是“加大堆内存”,而是先使用jmap或MAT分析堆Dump,找到占内存最多的对象,再回溯它的引用链。笔试会把这个过程简化为判断题或选择题,但背后的思路和线上排查完全一致。

关于垃圾回收器,G1是金融公司笔试的高频词,因为很多金融系统已经迁移到G1。你需要能说清G1的Region划分、可预测的停顿时间模型(-XX:MaxGCPauseMillis)以及RSet的维护成本。笔试题更狠的问法是:为什么不建议把G1的停顿时间目标设得太低?因为停顿时间目标越短,G1就越激进地做GC,GC频率会升高,吞吐量反而下降。这与“为什么负载因子是0.75而不是0.5”背后的取舍逻辑一脉相承。

4. Spring核心机制与数据库:笔试题里分值最大的两个重头

4.1 Spring Bean的生命周期:从构造到销毁,每一步都可能成为考点

Spring相关题目在Java笔试题中占比很高,核心考点非常集中:Bean的生命周期、依赖注入的方式、事务传播机制、AOP的底层原理。其中Bean生命周期是必考,而且经常以“给一段配置问执行顺序”的形式出现。

完整顺序是这样的:实例化Bean对象、填充属性(依赖注入)、执行Aware接口方法(BeanNameAware、BeanFactoryAware、ApplicationContextAware)、调用BeanPostProcessor的postProcessBeforeInitialization、执行@PostConstruct注解的初始化方法、调用InitializingBean的afterPropertiesSet、调用自定义init-method、调用BeanPostProcessor的postProcessAfterInitialization,最后是Bean的使用阶段。容器关闭时,依次执行@PreDestroy、DisposableBean的destroy方法和自定义destroy-method。

笔试最常挖的坑是@PostConstruct和afterPropertiesSet的执行顺序,以及BeanPostProcessor与InitializingBean的关系。我建议把执行顺序整理成一个表格,笔试前最后两小时专门背一遍,这一块的分数很容易拿全。

4.2 事务传播机制:required和required_new的差别,金融场景必考

事务传播机制是金融公司笔试题的重灾区,因为金融业务对事务边界极其敏感。默认的REQUIRED传播级别表示:如果当前没有事务,就新建一个;如果已经存在事务,就加入当前事务。而REQUIRES_NEW则是无论如何都新建一个独立事务,外层事务的回滚不影响内层事务已提交的结果。

这道题最常见的出法是给一个场景:服务A调用服务B,A有事务注解,B有REQUIRES_NEW事务注解,B执行成功后A抛出异常。问B的操作是否被回滚?答案是B不会被回滚,因为B运行在独立事务中。如果B是REQUIRED级别,则会和A处于同一事务,A回滚时B一并回滚。

很多人在笔试里栽在Spring事务的“自调用失效”问题上——同一个类内部调用带@Transactional注解的方法,事务不会生效。原因是Spring事务基于AOP代理,内部调用走的是this对象而不是代理对象,所以切面拦截不到。这个知识点也延伸到面试题的后续追问:怎么解决?常见方案是注入自身代理、拆分为不同类,或者用编程式事务TransactionTemplate。

4.3 SQL优化与索引失效:给了执行计划,你能不能说出慢在哪

数据库相关的笔试题通常有两种考查形式:一是给你一条SQL让你优化,二是给你一个索引设计让你判断是否合理。金融公司尤其关注这两个方向,因为数据库往往是系统的瓶颈所在。

索引失效的常见场景包括:对索引列使用函数或计算、隐式类型转换、LIKE以通配符开头、使用OR连接非索引列条件、索引列参与运算。笔试题经常给出一个查询条件让你判断是否走索引。其中隐藏的深水区是“隐式类型转换”——在MySQL中,如果索引列是varchar类型,查询参数是数字类型,优化器会先把varchar转成数字再比较,导致索引失效。

SQL优化层面,最常见的问题是深分页。limit 100000, 20这类翻页在数据量大时会扫描前十万行再丢弃,效率极低。业界常见优化手段是延迟关联或基于上一页最大ID的游标分页。笔试如果给出一张千万级流水表,问怎么高效分页,你需要表达出“避免大偏移量的limit,改用where id > 上一页最大值 order by id limit 20”这个思路。

索引设计方面,常考的坑是联合索引的最左前缀原则。给一个(a, b, c)联合索引,问哪些查询能用上索引:查a、查a和b、查a和b和c都能用上,查b和c、查c都用不上。笔试里更进阶的题目是问你查询条件里有a和c、但中间跳过了b时,a能用索引而c不能用——因为索引只能定位到a,无法直接定位到c。

5. 这些坑笔试必考:现象、原因与解决思路

5.1 HashSet存自定义对象后修改字段,contains却找不到对象

现象:把自定义对象放入HashSet,然后修改了参与hashCode计算的字段,再调用contains方法判断对象是否存在,返回false。

原因:对象放入HashSet时,hashCode决定了它存放在哪个桶。修改字段后,对象的hashCode变化了,但它在HashSet内部存储位置没有变。contains方法先按新hashCode找桶,自然找不到旧桶里的对象。

解决:不要修改放入HashSet或作为HashMap key的对象的字段;如果必须修改,先从集合中移除,修改后再放回去。笔试答题时写出“hashCode定位桶,桶内equals比较”这两层逻辑,基本能拿全分。

5.2 线程池execute和submit的异常吞没问题

现象:使用submit提交任务,任务内部抛出 RuntimeException,程序正常运行,控制台看不到异常堆栈。

原因:submit返回的Future对象,异常被封装在Future中,只有调用future.get()时才会抛出ExecutionException。如果代码没有获取Future,异常就被吞没了。

解决:execute没有返回值,异常会通过ThreadPoolExecutor内部的handleExecutionException机制向外抛出;submit则必须主动调用future.get()或使用execute。笔试题如果问“怎么保证线上任务异常能被及时发现”,要从两个层面答:一是任务内部做try-catch并记录日志,二是提交任务时对Future做异常包装处理。

5.3 事务自调用导致@Transactional失效

现象:同一类内,方法A调用方法B,A没有事务注解,B有@Transactional,B执行后抛出异常,但数据未回滚。

原因:Spring事务基于AOP动态代理,外部调用走代理,内部调用走this对象,B的切面逻辑没有被执行。

解决:最常见做法是把B拆到另一个类中,让外部调用触发代理。也可以用AopContext.currentProxy()获取当前代理对象,或者用TransactionTemplate做编程式事务。笔试会进一步问“代理失效还有哪些场景”,你得能说到private方法、final方法、非public方法都不能被CGLIB代理增强。

5.4 聚簇索引与二级索引的回表开销被忽略

现象:一条SQL明明走了二级索引,但响应还是很慢,执行计划显示Extra列为Using index condition,但实际消耗很高。

原因:二级索引查到主键值后,需要再回到聚簇索引取整行数据,这就是回表。如果查询的列不在索引中,每次命中都要回表,数据量大时开销成倍增加。

解决:用覆盖索引,让查询的所有列都包含在索引中,避免回表。笔试里的经典问法是“为什么不要用select * ”——除了网络传输开销外,*查询几乎必然导致回表。这个知识点在索引设计题里能与最左前缀原则联动,答出来就是加分项。

5.5 字符串拼接性能差距被低估

现象:一段用“+”拼接字符串的代码,在循环次数较大时性能明显下降,笔试代码题中的执行时间超出预期。

原因:String是不可变对象,“+”拼接在底层会创建StringBuilder并反复调用toString,循环次数多时产生大量中间对象,GC压力增大。

解决:循环次数已知时直接用StringBuilder,且初始化为合适容量避免扩容。笔试如果出“优化这段代码”的题目,改成StringBuilder并预设容量是最标准答案。

6. 算法题与笔试策略:最后的100分钟决定成败

金融科技公司的Java笔试题,最后两道题通常是算法设计或场景设计。算法题难度不会到竞赛级别,但集中在几个固定方向:数组操作、字符串处理、简单的动态规划、链表和二叉树的遍历。场景设计题则更像一个开放性问题,考察的是系统设计思维和数据结构的选型能力。

我见过的一道场景设计题是这样的:设计一个接口,支持高频调用,且需要记录最近5分钟的调用次数,要求空间和时间复杂度尽量低。这个题目可以引出滑动窗口、环形数组、时间戳队列几种方案。如果你用过环形缓冲区的思想实现过限流器,或者了解过Sentinel的滑动窗口计数器实现原理,答起来会从容很多。

笔试的时间分配也很讲究。我的习惯是:前面的基础题和概念题控制在40分钟内完成,遇到不确定的先跳过,不要在一道记忆模糊的题目上耗太久。中间部分的代码题留40分钟,最后20分钟留给场景题和检查。检查的重点不是重新读题干,而是看手写代码的边界条件——数组越界、空指针、循环终止条件,这些地方出错的比例远高于逻辑本身。

还有一个值得提的细节:手写代码题的评分标准通常是“先看思路对不对,再看代码能不能跑,最后看细节是否完整”。所以就算你记不全某个API的完整签名,用伪代码把核心逻辑写清楚,也远好过交白卷。面试官更看重的是你会不会解题,而不是背书背得多完整。

这道2020年的笔试题我前后做了三遍,每一遍都有新收获。第一遍是查漏补缺,发现自己对ConcurrentHashMap的弱一致性理解不到位;第二遍是把每道错题对应到源码和官方文档,补齐底层认知;第三遍是限时模拟,训练自己在压力下的状态。如果你也准备走金融科技方向,我建议按这个节奏来,别只刷题不深挖。笔试这件事,刷的是熟练度,深挖的是理解力,两者缺一不可。希望这份拆解能帮你少走一些弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 23:02:16

数据结构与算法习题答案docx实战:版本核对到高效复习指南

简介:《数据结构与算法分析(Java语言描述)》(第三版)习题答案文档,面向以Java语言学习数据结构与算法的学生,尤其适合备考期末、考研复试或课后自测。整体为1个docx文档,压缩包约1.5…

作者头像 李华
网站建设 2026/10/29 14:02:56

零成本搭建个人AI API聚合网关:2026年保姆级实战教程

个人开发者想低成本用上多家大模型,有个经典玩法:用开源项目 One-API 搭一个自己的聚合网关,把多家厂商的免费额度统一成一个 OpenAI 格式接口,换模型不改代码。本文是 2026 年版的保姆级教程,从网关选型一路讲到运维进阶。网关选型:为什么是 One-API 社区里三个主流方案各有千…

作者头像 李华
网站建设 2026/10/26 15:29:39

微电网多时间尺度调度优化MATLAB实现与工程实践

1. 项目背景与核心价值 微电网调度领域正面临一个关键挑战:如何协调不同响应速度的能源设备在分钟级到小时级时间尺度上的协同运行。传统单层调度模型往往难以兼顾光伏发电的秒级波动和燃气轮机的分钟级启停特性,这正是多时间尺度滚动优化技术的用武之地…

作者头像 李华
网站建设 2026/10/26 8:58:58

Git 将本地 Python 项目上传至 Gitee 完整教程|课程作业代码托管

前期准备安装 Git:官网下载 Git 并安装,安装完成后,在文件夹右键可以看到Git Bash Here。注册 Gitee 账号。准备好本地 Python 项目文件夹,里面存放.py源代码文件。第一步:在 Gitee 网页新建远程仓库登录 Gitee&#x…

作者头像 李华
网站建设 2026/10/25 11:08:44

Excel与JSON互转:语义保真转换实战指南

简介:这是一款面向开发人员、数据工程师及办公自动化需求者的轻量级Excel与JSON互转工具,解决日常数据格式转换中嵌套结构处理难、多工作表映射不清晰、类型转换易出错等痛点,适用于API调试、配置导出导入、测试数据生成等典型场景。资源包共…

作者头像 李华