简介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返回truehashCode却不相等。把这两个对象放进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等待150msCPU计算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就越激进地做GCGC频率会升高吞吐量反而下降。这与“为什么负载因子是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调用服务BA有事务注解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调用方法BA没有事务注解B有TransactionalB执行后抛出异常但数据未回滚。原因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的弱一致性理解不到位第二遍是把每道错题对应到源码和官方文档补齐底层认知第三遍是限时模拟训练自己在压力下的状态。如果你也准备走金融科技方向我建议按这个节奏来别只刷题不深挖。笔试这件事刷的是熟练度深挖的是理解力两者缺一不可。希望这份拆解能帮你少走一些弯路。本文还有配套的精品资源点击获取